re-repurpose cust_bill_pkg
authorjeff <jeff>
Fri, 12 Sep 2008 02:28:46 +0000 (02:28 +0000)
committerjeff <jeff>
Fri, 12 Sep 2008 02:28:46 +0000 (02:28 +0000)
FS/FS/Schema.pm
FS/FS/cust_bill.pm
FS/FS/cust_bill_pkg.pm
FS/FS/cust_bill_pkg_display.pm [new file with mode: 0644]
FS/FS/cust_main.pm
FS/MANIFEST
FS/t/cust_bill_pkg_display.t [new file with mode: 0644]

index d354561..c0fd466 100644 (file)
@@ -519,42 +519,25 @@ sub tables_hashref {
       ],
       'primary_key' => 'detailnum',
       'unique' => [],
-      'index' => [ [ 'billpkgnum' ], [ 'pkgnum', 'invnum' ] ],
+      'index' => [ [ 'billpkgnum' ], [ 'classnum' ], [ 'pkgnum', 'invnum' ] ],
     },
 
-    #instead of 'duplicate',  'char', 'NULL', 1, '', '',
-    # that way we keep display vs *TOTALLY* out of the table for actual
-    #  finanancial line items
     'cust_bill_pkg_display' => {
       'columns' => [
         'billpkgdisplaynum', 'serial', '', '', '', '', 
         'billpkgnum', 'int', '', '', '', '', 
         'section',  'varchar', 'NULL', $char_d, '', '', 
-        #override the linked real one?#'unitsetup', @money_typen, '', '', 
-        #this too?#'unitrecur', @money_typen, '', '', 
+        #'unitsetup', @money_typen, '', '',     #override the linked real one?
+        #'unitrecur', @money_typen, '', '',     #this too?
         'post_total', 'char', 'NULL', 1, '', '',
         'type',       'char', 'NULL', 1, '', '',
-        #any other fields we need to control this display-only line item...
+        'summary',    'char', 'NULL', 1, '', '',
       ],
       'primary_key' => 'billpkgdisplaynum',
       'unique' => [],
       'index' => [ ['billpkgnum'], ],
     },
 
-    #and this, to break down a line item into slices for taxation purposes
-    #(instead of creating usage line items for each usage class)
-    'cust_bill_pkg_slice' => {
-      'columns' => [
-        'slicenum', 'serial', '', '', '', '', 
-        'billpkgnum', 'int', '', '', '', '',
-        'amount',  @money_typen, '', '', 
-        'classnum', 'int', '', '', '', '',
-      ],
-      'primary_key' => 'slicenum',
-      'unique'      => [],
-      'index'       => [ [ 'billpkgnum' ], [ 'classnum' ], ],
-    },
-
     'cust_credit' => {
       'columns' => [
         'crednum',  'serial', '', '', '', '', 
index 61ae6c0..83a7965 100644 (file)
@@ -17,6 +17,7 @@ use FS::Record qw( qsearch qsearchs dbh );
 use FS::cust_main_Mixin;
 use FS::cust_main;
 use FS::cust_bill_pkg;
+use FS::cust_bill_pkg_display;
 use FS::cust_credit;
 use FS::cust_pay;
 use FS::cust_pkg;
@@ -2598,31 +2599,54 @@ sub _items_sections {
   {
 
     if ( $cust_bill_pkg->pkgnum > 0 ) {
+      my $usage = $cust_bill_pkg->usage;
+
+      foreach my $display ($cust_bill_pkg->cust_bill_pkg_display) {
+        my $desc = $display->section;
+        my $type = $display->type;
+
+        if ( $display->post_total ) {
+          if (! $type || $type eq 'S') {
+            $l{$desc} += $cust_bill_pkg->setup
+              if ( $cust_bill_pkg->setup != 0 );
+          }
+
+          if (! $type) {
+            $l{$desc} += $cust_bill_pkg->recur
+              if ( $cust_bill_pkg->recur != 0 );
+          }
+
+          if ($type && $type eq 'R') {
+            $l{$desc} += $cust_bill_pkg->recur - $usage
+              if ( $cust_bill_pkg->recur != 0 );
+          }
+          
+          if ($type && $type eq 'U') {
+            $l{$desc} += $usage;
+          }
+
+        } else {
+          if (! $type || $type eq 'S') {
+            $s{$desc} += $cust_bill_pkg->setup
+              if ( $cust_bill_pkg->setup != 0 );
+          }
+
+          if (! $type) {
+            $s{$desc} += $cust_bill_pkg->recur
+              if ( $cust_bill_pkg->recur != 0 );
+          }
+
+          if ($type && $type eq 'R') {
+            $s{$desc} += $cust_bill_pkg->recur - $usage
+              if ( $cust_bill_pkg->recur != 0 );
+          }
+          
+          if ($type && $type eq 'U') {
+            $s{$desc} += $usage;
+          }
 
-      my $desc = $cust_bill_pkg->section;
-      my $dup_desc = $cust_bill_pkg->duplicate_section;
-
-      if ($cust_bill_pkg->duplicate) {
-        $s{$dup_desc} += $cust_bill_pkg->setup
-          if ( $cust_bill_pkg->setup != 0 );
-
-        $s{$dup_desc} += $cust_bill_pkg->recur
-          if ( $cust_bill_pkg->recur != 0 );
-      }
-
-      if ( $cust_bill_pkg->post_total ) {
-        $l{$desc} += $cust_bill_pkg->setup
-          if ( $cust_bill_pkg->setup != 0 );
-
-        $l{$desc} += $cust_bill_pkg->recur
-          if ( $cust_bill_pkg->recur != 0 );
-
-      } else {
-        $s{$desc} += $cust_bill_pkg->setup
-          if ( $cust_bill_pkg->setup != 0 );
+        }
 
-        $s{$desc} += $cust_bill_pkg->recur
-          if ( $cust_bill_pkg->recur != 0 );
       }
 
     }
@@ -2690,13 +2714,7 @@ sub _items_pkg {
   my %options = @_;
   my $section = $options{'section'};
   my $desc = $section->{'description'};
-  my @cust_bill_pkg =
-    grep { $_->pkgnum &&
-           ( defined($section)
-               ? ( $_->section eq $desc || $_->duplicate_section eq $desc )
-               : 1
-           )
-         } $self->cust_bill_pkg;
+  my @cust_bill_pkg = grep { $_->pkgnum } $self->cust_bill_pkg;
   $self->_items_cust_bill_pkg(\@cust_bill_pkg, %options);
 }
 
@@ -2724,86 +2742,94 @@ sub _items_cust_bill_pkg {
   my $escape_function = $opt{escape_function} || sub { shift };
   my $format_function = $opt{format_function} || '';
   my $unsquelched = $opt{unsquelched} || '';
+  my $section = $opt{section}->{description} if $opt{section};
 
   my @b = ();
-  my $last_pkgnum = '';
   foreach my $cust_bill_pkg ( @$cust_bill_pkg )
   {
+    foreach my $display ( grep { defined($section)
+                                 ? $_->section eq $section
+                                 : 1
+                               }
+                          $cust_bill_pkg->cust_bill_pkg_display
+                        )
+    {
 
-    my $cust_pkg = $cust_bill_pkg->cust_pkg;
-
-    my $desc = $cust_bill_pkg->desc;
-
-    my %details_opt = ( 'format'          => $format,
-                        'escape_function' => $escape_function,
-                        'format_function' => $format_function,
-                      );
-
-    if ( $cust_bill_pkg->pkgnum > 0 ) {
+      my $type = $display->type;
 
-      if ( $cust_bill_pkg->setup != 0 ) {
+      my $cust_pkg = $cust_bill_pkg->cust_pkg;
 
-        my $description = $desc;
-        $description .= ' Setup' if $cust_bill_pkg->recur != 0;
+      my $desc = $cust_bill_pkg->desc;
 
-        my @d = map &{$escape_function}($_),
-                       $cust_pkg->h_labels_short($self->_date);
-        push @d, $cust_bill_pkg->details(%details_opt)
-          if $cust_bill_pkg->recur == 0;
+      my %details_opt = ( 'format'          => $format,
+                          'escape_function' => $escape_function,
+                          'format_function' => $format_function,
+                        );
 
-        push @b, {
-          description     => $description,
-          #pkgpart         => $part_pkg->pkgpart,
-          pkgnum          => $cust_bill_pkg->pkgnum,
-          amount          => sprintf("%.2f", $cust_bill_pkg->setup),
-          unit_amount     => sprintf("%.2f", $cust_bill_pkg->unitsetup),
-          quantity        => $cust_bill_pkg->quantity,
-          ext_description => \@d,
-        };
+      if ( $cust_bill_pkg->pkgnum > 0 ) {
 
-        $last_pkgnum = '';
+        if ( $cust_bill_pkg->setup != 0 && (!$type || $type eq 'S') ) {
 
-      }
+          my $description = $desc;
+          $description .= ' Setup' if $cust_bill_pkg->recur != 0;
 
-      if ( $cust_bill_pkg->recur != 0 ) {
+          my @d = map &{$escape_function}($_),
+                         $cust_pkg->h_labels_short($self->_date);
+          push @d, $cust_bill_pkg->details(%details_opt)
+            if $cust_bill_pkg->recur == 0;
 
-        my $is_summary =
-          ( $cust_bill_pkg->duplicate && 
-            $opt{section}->{description} ne $cust_bill_pkg->section
-          );
-        my $description = $is_summary ? "Usage charges" : $desc;
+          push @b, {
+            description     => $description,
+            #pkgpart         => $part_pkg->pkgpart,
+            pkgnum          => $cust_bill_pkg->pkgnum,
+            amount          => sprintf("%.2f", $cust_bill_pkg->setup),
+            unit_amount     => sprintf("%.2f", $cust_bill_pkg->unitsetup),
+            quantity        => $cust_bill_pkg->quantity,
+            ext_description => \@d,
+          };
 
-        unless ( $conf->exists('disable_line_item_date_ranges') ) {
-          $description .= " (" . time2str("%x", $cust_bill_pkg->sdate).
-                          " - ". time2str("%x", $cust_bill_pkg->edate). ")";
         }
 
-        #at least until cust_bill_pkg has "past" ranges in addition to
-        #the "future" sdate/edate ones... see #3032
-        my @d = ();
-        push @d, map &{$escape_function}($_),
-                       $cust_pkg->h_labels_short($self->_date)
-                                              #$cust_bill_pkg->edate,
-                                              #$cust_bill_pkg->sdate),
-          unless ($cust_bill_pkg->pkgnum eq $last_pkgnum);
-
-        @d = () if ($cust_bill_pkg->itemdesc || $is_summary);
-        push @d, $cust_bill_pkg->details(%details_opt)
-          unless $is_summary;
-
-        if ($cust_bill_pkg->pkgnum eq $last_pkgnum) {
-
-          $b[$#b]->{amount} =
-            sprintf("%.2f", $b[$#b]->{amount} + $cust_bill_pkg->recur);
-          push @{$b[$#b]->{ext_description}}, @d;
-
-        }else{
-
+        if ( $cust_bill_pkg->recur != 0 &&
+             ( !$type || $type eq 'R' || $type eq 'U' )
+           )
+        {
+
+          my $is_summary = $display->summary;
+          my $description = $is_summary ? "Usage charges" : $desc;
+
+          unless ( $conf->exists('disable_line_item_date_ranges') ) {
+            $description .= " (" . time2str("%x", $cust_bill_pkg->sdate).
+                            " - ". time2str("%x", $cust_bill_pkg->edate). ")";
+          }
+
+          #at least until cust_bill_pkg has "past" ranges in addition to
+          #the "future" sdate/edate ones... see #3032
+          my @d = ();
+          push @d, map &{$escape_function}($_),
+                         $cust_pkg->h_labels_short($self->_date)
+                                                #$cust_bill_pkg->edate,
+                                                #$cust_bill_pkg->sdate),
+            ;
+  
+          @d = () if ($cust_bill_pkg->itemdesc || $is_summary);
+          push @d, $cust_bill_pkg->details(%details_opt)
+            unless ($is_summary || $type && $type eq 'R');
+  
+          my $amount = 0;
+          if (!$type) {
+            $amount = $cust_bill_pkg->recur;
+          }elsif($type eq 'R') {
+            $amount = $cust_bill_pkg->recur - $cust_bill_pkg->usage;
+          }elsif($type eq 'U') {
+            $amount = $cust_bill_pkg->usage;
+          }
+  
           push @b, {
             description     => $description,
             #pkgpart         => $part_pkg->pkgpart,
             pkgnum          => $cust_bill_pkg->pkgnum,
-            amount          => sprintf("%.2f", $cust_bill_pkg->recur),
+            amount          => sprintf("%.2f", $amount),
             unit_amount     => sprintf("%.2f", $cust_bill_pkg->unitrecur),
             quantity        => $cust_bill_pkg->quantity,
             ext_description => \@d,
@@ -2811,31 +2837,24 @@ sub _items_cust_bill_pkg {
 
         }
 
-        if ($conf->exists('separate_usage') && $cust_bill_pkg->type ne 'U') {
-          $last_pkgnum = '';
-        }else{
-          $last_pkgnum = $cust_bill_pkg->pkgnum;
-        }
-      }
+      } else { #pkgnum tax or one-shot line item (??)
 
-    } else { #pkgnum tax or one-shot line item (??)
+        if ( $cust_bill_pkg->setup != 0 ) {
+          push @b, {
+            'description' => $desc,
+            'amount'      => sprintf("%.2f", $cust_bill_pkg->setup),
+          };
+        }
+        if ( $cust_bill_pkg->recur != 0 ) {
+          push @b, {
+            'description' => "$desc (".
+                             time2str("%x", $cust_bill_pkg->sdate). ' - '.
+                             time2str("%x", $cust_bill_pkg->edate). ')',
+            'amount'      => sprintf("%.2f", $cust_bill_pkg->recur),
+          };
+        }
 
-      if ( $cust_bill_pkg->setup != 0 ) {
-        push @b, {
-          'description' => $desc,
-          'amount'      => sprintf("%.2f", $cust_bill_pkg->setup),
-        };
       }
-      if ( $cust_bill_pkg->recur != 0 ) {
-        push @b, {
-          'description' => "$desc (".
-                           time2str("%x", $cust_bill_pkg->sdate). ' - '.
-                           time2str("%x", $cust_bill_pkg->edate). ')',
-          'amount'      => sprintf("%.2f", $cust_bill_pkg->recur),
-        };
-      }
-
-      $last_pkgnum = '';
 
     }
 
index 2bfde6d..ddda504 100644 (file)
@@ -1,18 +1,21 @@
 package FS::cust_bill_pkg;
 
 use strict;
-use vars qw( @ISA );
+use vars qw( @ISA $DEBUG );
 use FS::Record qw( qsearch qsearchs dbdef dbh );
 use FS::cust_main_Mixin;
 use FS::cust_pkg;
 use FS::part_pkg;
 use FS::cust_bill;
 use FS::cust_bill_pkg_detail;
+use FS::cust_bill_pkg_display;
 use FS::cust_bill_pay_pkg;
 use FS::cust_credit_bill_pkg;
 
 @ISA = qw( FS::cust_main_Mixin FS::Record );
 
+$DEBUG = 0;
+
 =head1 NAME
 
 FS::cust_bill_pkg - Object methods for cust_bill_pkg records
@@ -57,24 +60,6 @@ supported:
 
 =item itemdesc - Line item description (overrides normal package description)
 
-=item section - Invoice section (overrides normal package section)
-
-=cut
-
-sub section {
-  my ( $self, $value ) = @_;
-  if ( defined($value) ) {
-    $self->setfield('section', $value);
-  } else {
-    $self->getfield('section') || $self->part_pkg->categoryname;
-  }
-}
-
-sub duplicate_section {
-  my $self = shift;
-  $self->duplicate ? $self->part_pkg->categoryname : '';
-}
-
 =item quantity - If not set, defaults to 1
 
 =item unitsetup - If not set, defaults to setup
@@ -127,23 +112,31 @@ sub insert {
     return $error;
   }
 
-  unless ( defined dbdef->table('cust_bill_pkg_detail') && $self->get('details') ) {
-    $dbh->commit or die $dbh->errstr if $oldAutoCommit;
-    return '';
+  if ( defined dbdef->table('cust_bill_pkg_detail') && $self->get('details') ) {
+    foreach my $detail ( @{$self->get('details')} ) {
+      my $cust_bill_pkg_detail = new FS::cust_bill_pkg_detail {
+        'billpkgnum' => $self->billpkgnum,
+        'format'     => (ref($detail) ? $detail->[0] : '' ),
+        'detail'     => (ref($detail) ? $detail->[1] : $detail ),
+        'amount'     => (ref($detail) ? $detail->[2] : '' ),
+        'classnum'   => (ref($detail) ? $detail->[3] : '' ),
+      };
+      $error = $cust_bill_pkg_detail->insert;
+      if ( $error ) {
+        $dbh->rollback if $oldAutoCommit;
+        return $error;
+      }
+    }
   }
 
-  foreach my $detail ( @{$self->get('details')} ) {
-    my $cust_bill_pkg_detail = new FS::cust_bill_pkg_detail {
-      'billpkgnum' => $self->billpkgnum,
-      'format'     => (ref($detail) ? $detail->[0] : '' ),
-      'detail'     => (ref($detail) ? $detail->[1] : $detail ),
-      'amount'     => (ref($detail) ? $detail->[2] : '' ),
-      'classnum'   => (ref($detail) ? $detail->[3] : '' ),
-    };
-    $error = $cust_bill_pkg_detail->insert;
-    if ( $error ) {
-      $dbh->rollback if $oldAutoCommit;
-      return $error;
+  if ( defined dbdef->table('cust_bill_pkg_display') && $self->get('display') ){
+    foreach my $cust_bill_pkg_display ( @{ $self->get('display') } ) {
+      $cust_bill_pkg_display->billpkgnum($self->billpkgnum);
+      $error = $cust_bill_pkg_display->insert;
+      if ( $error ) {
+        $dbh->rollback if $oldAutoCommit;
+        return $error;
+      }
     }
   }
 
@@ -194,7 +187,6 @@ sub check {
       || $self->ut_numbern('sdate')
       || $self->ut_numbern('edate')
       || $self->ut_textn('itemdesc')
-      || $self->ut_textn('section')
   ;
   return $error if $error;
 
@@ -446,6 +438,79 @@ sub unitrecur {
     : $self->getfield('unitrecur');
 }
 
+=item disintegrate
+
+Returns a list of cust_bill_pkg objects each with no more than a single class
+(including setup or recur) of charge.
+
+=cut
+
+sub disintegrate {
+  my $self = shift;
+  # XXX this goes away with cust_bill_pkg refactor
+
+  my $cust_bill_pkg = new FS::cust_bill_pkg { $self->hash };
+  my %cust_bill_pkg = ();
+
+  $cust_bill_pkg{setup} = $cust_bill_pkg if $cust_bill_pkg->setup;
+  $cust_bill_pkg{recur} = $cust_bill_pkg if $cust_bill_pkg->recur;
+
+
+  #split setup and recur
+  if ($cust_bill_pkg->setup && $cust_bill_pkg->recur) {
+    my $cust_bill_pkg_recur = new FS::cust_bill_pkg { $cust_bill_pkg->hash };
+    $cust_bill_pkg->set('details', []);
+    $cust_bill_pkg->recur(0);
+    $cust_bill_pkg->unitrecur(0);
+    $cust_bill_pkg->type('');
+    $cust_bill_pkg_recur->setup(0);
+    $cust_bill_pkg_recur->unitsetup(0);
+    $cust_bill_pkg{recur} = $cust_bill_pkg_recur;
+
+  }
+
+  #split usage from recur
+  my $usage = sprintf( "%.2f", $cust_bill_pkg{recur}->usage );
+  warn "usage is $usage\n" if $DEBUG;
+  if ($usage) {
+    my $cust_bill_pkg_usage =
+        new FS::cust_bill_pkg { $cust_bill_pkg{recur}->hash };
+    $cust_bill_pkg_usage->recur( $usage );
+    $cust_bill_pkg_usage->type( 'U' );
+    my $recur = sprintf( "%.2f", $cust_bill_pkg{recur}->recur - $usage );
+    $cust_bill_pkg{recur}->recur( $recur );
+    $cust_bill_pkg{recur}->type( '' );
+    $cust_bill_pkg{recur}->set('details', []);
+    $cust_bill_pkg{''} = $cust_bill_pkg_usage;
+  }
+
+  #subdivide usage by usage_class
+  if (exists($cust_bill_pkg{''})) {
+    foreach my $class (grep { $_ } $self->usage_classes) {
+      my $usage = sprintf( "%.2f", $cust_bill_pkg{''}->usage($class) );
+      my $cust_bill_pkg_usage =
+          new FS::cust_bill_pkg { $cust_bill_pkg{''}->hash };
+      $cust_bill_pkg_usage->recur( $usage );
+      $cust_bill_pkg_usage->set('details', []);
+      my $classless = sprintf( "%.2f", $cust_bill_pkg{''}->recur - $usage );
+      $cust_bill_pkg{''}->recur( $classless );
+      $cust_bill_pkg{$class} = $cust_bill_pkg_usage;
+    }
+    delete $cust_bill_pkg{''} unless $cust_bill_pkg{''}->recur;
+  }
+
+#  # sort setup,recur,'', and the rest numeric && return
+#  my @result = map { $cust_bill_pkg{$_} }
+#               sort { my $ad = ($a=~/^\d+$/); my $bd = ($b=~/^\d+$/);
+#                      ( $ad cmp $bd ) || ( $ad ? $a<=>$b : $b cmp $a )
+#                    }
+#               keys %cust_bill_pkg;
+#
+#  return (@result);
+
+   %cust_bill_pkg;
+}
+
 =item usage CLASSNUM
 
 Returns the amount of the charge associated with usage class CLASSNUM if
@@ -510,6 +575,44 @@ sub usage_classes {
 
 }
 
+=item cust_bill_pkg_display [ type => TYPE ]
+
+Returns an array of display information for the invoice line item optionally
+limited to 'TYPE'.
+
+=cut
+
+sub cust_bill_pkg_display {
+  my ( $self, %opt ) = @_;
+
+  my $default =
+    new FS::cust_bill_pkg_display { billpkgnum =>$self->billpkgnum };
+
+  return ( $default ) unless defined dbdef->table('cust_bill_pkg_display');#hmmm
+
+  my $type = $opt{type} if exists $opt{type};
+  my @result;
+
+  if ( scalar( $self->get('display') ) ) {
+    @result = grep { defined($type) ? ($type eq $_->type) : 1 }
+              @{ $self->get('display') };
+  }else{
+    my $hashref = { 'billpkgnum' => $self->billpkgnum };
+    $hashref->{type} = $type if defined($type);
+    
+    @result = qsearch ({ 'table'    => 'cust_bill_pkg_display',
+                         'hashref'  => { 'billpkgnum' => $self->billpkgnum },
+                         'order_by' => 'ORDER BY billpkgdisplaynum',
+                      });
+  }
+
+  push @result, $default unless ( scalar(@result) || $type );
+
+  @result;
+
+}
+
+
 =back
 
 =head1 BUGS
diff --git a/FS/FS/cust_bill_pkg_display.pm b/FS/FS/cust_bill_pkg_display.pm
new file mode 100644 (file)
index 0000000..93c6e87
--- /dev/null
@@ -0,0 +1,158 @@
+package FS::cust_bill_pkg_display;
+
+use strict;
+use vars qw( @ISA );
+use FS::Record qw( qsearch qsearchs );
+
+@ISA = qw(FS::Record);
+
+=head1 NAME
+
+FS::cust_bill_pkg_display - Object methods for cust_bill_pkg_display records
+
+=head1 SYNOPSIS
+
+  use FS::cust_bill_pkg_display;
+
+  $record = new FS::cust_bill_pkg_display \%hash;
+  $record = new FS::cust_bill_pkg_display { 'column' => 'value' };
+
+  $error = $record->insert;
+
+  $error = $new_record->replace($old_record);
+
+  $error = $record->delete;
+
+  $error = $record->check;
+
+=head1 DESCRIPTION
+
+An FS::cust_bill_pkg_display object represents line item display information.
+FS::cust_bill_pkg_display inherits from FS::Record.  The following fields are
+currently supported:
+
+=over 4
+
+=item billpkgdisplaynum
+
+primary key
+
+=item billpkgnum
+
+billpkgnum
+
+=item section
+
+section
+
+=cut
+
+sub section {
+  my ( $self, $value ) = @_;
+  if ( defined($value) ) {
+    $self->setfield('section', $value);
+  } else {
+    $self->getfield('section') || $self->cust_bill_pkg->part_pkg->categoryname;
+  }
+}
+
+=item post_total
+
+post_total
+
+=item type
+
+type
+
+=item summary
+
+summary
+
+=back
+
+=head1 METHODS
+
+=over 4
+
+=item new HASHREF
+
+Creates a new line item display object.  To add the record to the database, see L<"insert">.
+
+Note that this stores the hash reference, not a distinct copy of the hash it
+points to.  You can ask the object for a copy with the I<hash> method.
+
+=cut
+
+sub table { 'cust_bill_pkg_display'; }
+
+=item insert
+
+Adds this record to the database.  If there is an error, returns the error,
+otherwise returns false.
+
+=cut
+
+=item delete
+
+Delete this record from the database.
+
+=cut
+
+=item replace OLD_RECORD
+
+Replaces the OLD_RECORD with this one in the database.  If there is an error,
+returns the error, otherwise returns false.
+
+=cut
+
+=item check
+
+Checks all fields to make sure this is a valid line item display object.
+If there is an error, returns the error, otherwise returns false.  Called by
+the insert and replace methods.
+
+=cut
+
+sub check {
+  my $self = shift;
+
+  my $error = 
+    $self->ut_numbern('billpkgdisplaynum')
+    || $self->ut_number('billpkgnum')
+    || $self->ut_foreign_key('billpkgnum', 'cust_bill_pkg', 'billpkgnum')
+    || $self->ut_textn('section')
+    || $self->ut_enum('post_total', [ '', 'Y' ])
+    || $self->ut_enum('type', [ '', 'S', 'R', 'U' ])
+    || $self->ut_enum('summary', [ '', 'Y' ])
+  ;
+  return $error if $error;
+
+  $self->SUPER::check;
+}
+
+=item cust_bill_pkg
+
+Returns the associated cust_bill_pkg (see L<FS::cust_bill_pkg>) for this
+line item display object.
+
+=cut
+
+sub cust_bill_pkg {
+  my $self = shift;
+  qsearchs( 'cust_bill_pkg', { 'billpkgnum' => $self->billpkgnum } ) ;
+}
+
+=back
+
+=head1 BUGS
+
+
+
+=head1 SEE ALSO
+
+L<FS::Record>, L<FS::cust_bill_pkg>, schema.html from the base documentation.
+
+=cut
+
+1;
+
index e64d666..88d8bdd 100644 (file)
@@ -29,6 +29,7 @@ use FS::cust_pkg;
 use FS::cust_svc;
 use FS::cust_bill;
 use FS::cust_bill_pkg;
+use FS::cust_bill_pkg_display;
 use FS::cust_pay;
 use FS::cust_pay_pending;
 use FS::cust_pay_void;
@@ -2567,89 +2568,40 @@ sub _handle_taxes {
 
   } #if $conf->exists('enable_taxproducts') ...
  
-  my $section = $cust_pkg->part_pkg->option('usage_section', 'Hush!')
-    if $cust_pkg->part_pkg->option('separate_usage', 'Hush!' );
-  my $want_duplicate =
-    $cust_pkg->part_pkg->option('summarize_usage', 'Hush!') &&
-    $cust_pkg->part_pkg->option('usage_section', 'Hush!');
+  my @display = ();
+  if ( $conf->exists('separate_usage') ) {
+    my $section = $cust_pkg->part_pkg->option('usage_section', 'Hush!');
+    my $summary = $cust_pkg->part_pkg->option('summarize_usage', 'Hush!');
+    push @display, new FS::cust_bill_pkg_display { type    => 'S' };
+    push @display, new FS::cust_bill_pkg_display { type    => 'R' };
+    push @display, new FS::cust_bill_pkg_display { type    => 'U',
+                                                   section => $section
+                                                 };
+    if ($section && $summary) {
+      $display[2]->post_total('Y');
+      push @display, new FS::cust_bill_pkg_display { type    => 'U',
+                                                     summary => 'Y',
+                                                   }
+    }
+  }
+  $cust_bill_pkg->set('display', \@display);
 
-#BUNK.  DO NOT CREATE DUPLICATE cust_bill_pkg!!!!!!!!!!!!
-#
-#  # XXX this mostly goes away with cust_bill_pkg refactor
-# 
-#  $cust_bill_pkg{setup} = $cust_bill_pkg if $cust_bill_pkg->setup;
-#  $cust_bill_pkg{recur} = $cust_bill_pkg if $cust_bill_pkg->recur;
-#
-#    
-#  #split setup and recur
-#  if ($cust_bill_pkg->setup && $cust_bill_pkg->recur) {
-#    my $cust_bill_pkg_recur = new FS::cust_bill_pkg { $cust_bill_pkg->hash };
-#    $cust_bill_pkg_recur->details($cust_bill_pkg->
-#    $cust_bill_pkg_recur->setup(0);
-#    $cust_bill_pkg_recur->unitsetup(0);
-#    $cust_bill_pkg{recur} = $cust_bill_pkg_recur;
-#
-#    $cust_bill_pkg->set('details', []);
-#    $cust_bill_pkg->recur(0);
-#    $cust_bill_pkg->unitrecur(0);
-#    $cust_bill_pkg->type('');
-#  }
-#
-#  #split usage from recur
-#  my $usage = sprintf( "%.2f", $cust_bill_pkg{recur}->usage );
-#  warn "usage is $usage\n" if $DEBUG;
-#  if ($usage) {
-#    my $cust_bill_pkg_usage =
-#        new FS::cust_bill_pkg { $cust_bill_pkg{recur}->hash };
-#    $cust_bill_pkg_usage->recur( $usage );
-#    $cust_bill_pkg_usage->type( 'U' );
-#    $cust_bill_pkg_usage->duplicate( $want_duplicate ? 'Y' :  '' );
-#    $cust_bill_pkg_usage->section( $section );
-#    $cust_bill_pkg_usage->post_total( $want_duplicate ? 'Y' :  '' );
-#    my $recur = sprintf( "%.2f", $cust_bill_pkg{recur}->recur - $usage );
-#    $cust_bill_pkg{recur}->recur( $recur );
-#    $cust_bill_pkg{recur}->type( '' );
-#    $cust_bill_pkg{recur}->set('details', []);
-#    $cust_bill_pkg{''} = $cust_bill_pkg_usage;
-#  }
-#
-#  #subdivide usage by usage_class
-#  if (exists($cust_bill_pkg{''})) {
-#    foreach my $class (grep {$_ && $_ ne 'setup' && $_ ne 'recur' } @classes) {
-#      my $usage = sprintf( "%.2f", $cust_bill_pkg{''}->usage($class) );
-#      my $cust_bill_pkg_usage =
-#          new FS::cust_bill_pkg { $cust_bill_pkg{''}->hash };
-#      $cust_bill_pkg_usage->recur( $usage );
-#      $cust_bill_pkg_usage->set('details', []);
-#      my $classless = sprintf( "%.2f", $cust_bill_pkg{''}->recur - $usage );
-#      $cust_bill_pkg{''}->recur( $classless );
-#      $cust_bill_pkg{$class} = $cust_bill_pkg_usage;
-#    }
-#    delete $cust_bill_pkg{''} unless $cust_bill_pkg{''}->recur;
-#  }
-#
-#  foreach my $key (keys %cust_bill_pkg) {
-#    my @taxes = @{ $taxes{$key} };
-#    my $cust_bill_pkg = $cust_bill_pkg{$key};
-#
-#    foreach my $tax ( @taxes ) {
-#      my $taxname = ref( $tax ). ' '. $tax->taxnum;
-#      if ( exists( $taxlisthash->{ $taxname } ) ) {
-#        push @{ $taxlisthash->{ $taxname  } }, $cust_bill_pkg;
-#      }else{
-#        $taxlisthash->{ $taxname } = [ $tax, $cust_bill_pkg ];
-#      }
-#    }
-#  }
-#
-#  # sort setup,recur,'', and the rest numeric && return
-#  my @result = map { $cust_bill_pkg{$_} }
-#               sort { my $ad = ($a=~/^\d+$/); my $bd = ($b=~/^\d+$/);
-#                      ( $ad cmp $bd ) || ( $ad ? $a<=>$b : $b cmp $a )
-#                    }
-#               keys %cust_bill_pkg;
-#
-#  \@result;
+  my %tax_cust_bill_pkg = $cust_bill_pkg->disintegrate;
+  foreach my $key (keys %tax_cust_bill_pkg) {
+    my @taxes = @{ $taxes{$key} };
+    my $tax_cust_bill_pkg = $tax_cust_bill_pkg{$key};
+
+    foreach my $tax ( @taxes ) {
+      my $taxname = ref( $tax ). ' '. $tax->taxnum;
+      if ( exists( $taxlisthash->{ $taxname } ) ) {
+        push @{ $taxlisthash->{ $taxname  } }, $tax_cust_bill_pkg;
+      }else{
+        $taxlisthash->{ $taxname } = [ $tax, $tax_cust_bill_pkg ];
+      }
+    }
+  }
+
+  '';
 }
 
 sub _gather_taxes {
index b1f201d..5bae060 100644 (file)
@@ -422,5 +422,7 @@ FS/cust_svc_option.pm
 t/cust_svc_option.t
 FS/usage_class.pm
 t/usage_class.t
+FS/cust_bill_pkg_display.pm
+t/cust_bill_pkg_display.t
 FS/cust_pkg_detail.pm
 t/cust_pkg_detail.t
diff --git a/FS/t/cust_bill_pkg_display.t b/FS/t/cust_bill_pkg_display.t
new file mode 100644 (file)
index 0000000..d84dbdf
--- /dev/null
@@ -0,0 +1,5 @@
+BEGIN { $| = 1; print "1..1\n" }
+END {print "not ok 1\n" unless $loaded;}
+use FS::cust_bill_pkg_display;
+$loaded=1;
+print "ok 1\n";