+ # 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 )
+ if exists($cust_bill_pkg{recur});
+ warn "usage is $usage\n" if $DEBUG > 1;
+ 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;
+ }
+ warn "Unexpected classless usage value: ". $cust_bill_pkg{''}->recur
+ if ($cust_bill_pkg{''}->recur && $cust_bill_pkg{''}->recur < 0);
+ delete $cust_bill_pkg{''}
+ unless ($cust_bill_pkg{''}->recur && $cust_bill_pkg{''}->recur > 0);
+ }
+
+# # 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
+CLASSNUM is defined. Otherwise returns the total charge associated with
+usage.
+
+=cut
+
+sub usage {
+ my( $self, $classnum ) = @_;
+ $self->regularize_details;
+
+ if ( $self->get('details') ) {
+
+ return sum( 0,
+ map { $_->amount || 0 }
+ grep { !defined($classnum) or $classnum eq $_->classnum }
+ @{ $self->get('details') }
+ );
+
+ } else {
+
+ my $sql = 'SELECT SUM(COALESCE(amount,0)) FROM cust_bill_pkg_detail '.
+ ' WHERE billpkgnum = '. $self->billpkgnum;
+ $sql .= " AND classnum = $classnum" if defined($classnum);
+
+ my $sth = dbh->prepare($sql) or die dbh->errstr;
+ $sth->execute or die $sth->errstr;
+
+ return $sth->fetchrow_arrayref->[0] || 0;
+
+ }
+
+}
+
+=item usage_classes
+
+Returns a list of usage classnums associated with this invoice line's
+details.
+
+=cut
+
+sub usage_classes {
+ my( $self ) = @_;
+ $self->regularize_details;
+
+ if ( $self->get('details') ) {
+
+ my %seen = ( map { $_->classnum => 1 } @{ $self->get('details') } );
+ keys %seen;