summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--FS/FS/cust_bill.pm26
-rw-r--r--FS/FS/cust_bill_pkg.pm29
-rw-r--r--FS/FS/usage_class.pm69
3 files changed, 103 insertions, 21 deletions
diff --git a/FS/FS/cust_bill.pm b/FS/FS/cust_bill.pm
index cefbfac..56099cc 100644
--- a/FS/FS/cust_bill.pm
+++ b/FS/FS/cust_bill.pm
@@ -3741,6 +3741,9 @@ sub _items_svc_phone_sections {
foreach my $cust_bill_pkg ( $self->cust_bill_pkg ) {
next unless $cust_bill_pkg->pkgnum > 0;
+ my @header = $cust_bill_pkg->details_header;
+ next unless scalar(@header);
+
foreach my $detail ( $cust_bill_pkg->cust_bill_pkg_detail ) {
my $phonenum = $detail->phonenum;
@@ -3789,6 +3792,7 @@ sub _items_svc_phone_sections {
'duration' => 0,
'sort_weight' => $usage_class{$detail->classnum}->weight,
'phonenum' => $phonenum,
+ 'header' => [ @header ],
};
$sections{"$phonenum $line"}{amount} += $amount; #subtotal
$sections{"$phonenum $line"}{calls}++;
@@ -3819,11 +3823,17 @@ sub _items_svc_phone_sections {
my %sectionmap = ();
my $simple = new FS::usage_class { format => 'simple' }; #bleh
- my $usage_simple = new FS::usage_class { format => 'usage_simple' }; #bleh
foreach ( keys %sections ) {
+ my @header = @{ $sections{$_}{header} || [] };
+ my $usage_simple =
+ new FS::usage_class { format => 'usage_'. (scalar(@header) || 6). 'col' };
my $summary = $sections{$_}{sort_weight} < 0 ? 1 : 0;
my $usage_class = $summary ? $simple : $usage_simple;
my $ending = $summary ? ' usage charges' : '';
+ my %gen_opt = ();
+ unless ($summary) {
+ $gen_opt{label} = [ map{ &{$escape}($_) } @header ];
+ }
$sectionmap{$_} = { 'description' => &{$escape}($_. $ending),
'amount' => $sections{$_}{amount}, #subtotal
'calls' => $sections{$_}{calls},
@@ -3834,7 +3844,7 @@ sub _items_svc_phone_sections {
'sort_weight' => $sections{$_}{sort_weight},
'post_total' => $summary, #inspire pagebreak
(
- ( map { $_ => $usage_class->$_($format) }
+ ( map { $_ => $usage_class->$_($format, %gen_opt) }
qw( description_generator
header_generator
total_generator
@@ -3943,12 +3953,12 @@ sub _items_pkg {
}
sub _taxsort {
- return 0 unless $a cmp $b;
- return -1 if $b eq 'Tax';
- return 1 if $a eq 'Tax';
- return -1 if $b eq 'Other surcharges';
- return 1 if $a eq 'Other surcharges';
- $a cmp $b;
+ return 0 unless $a->itemdesc cmp $b->itemdesc;
+ return -1 if $b->itemdesc eq 'Tax';
+ return 1 if $a->itemdesc eq 'Tax';
+ return -1 if $b->itemdesc eq 'Other surcharges';
+ return 1 if $a->itemdesc eq 'Other surcharges';
+ $a->itemdesc cmp $b->itemdesc;
}
sub _items_tax {
diff --git a/FS/FS/cust_bill_pkg.pm b/FS/FS/cust_bill_pkg.pm
index c825c15..d396f82 100644
--- a/FS/FS/cust_bill_pkg.pm
+++ b/FS/FS/cust_bill_pkg.pm
@@ -480,6 +480,35 @@ sub details {
#qsearch ( 'cust_bill_pkg_detail', { 'lineitemnum' => $self->lineitemnum });
}
+=item details_header [ OPTION => VALUE ... ]
+
+Returns a list representing an invoice line item detail header, if any.
+This relies on the behavior of voip_cdr in that it expects the header
+to be the first CSV formatted detail (as is expected by invoice generation
+routines). Returns the empty list otherwise.
+
+=cut
+
+sub details_header {
+ my $self = shift;
+ return '' unless defined dbdef->table('cust_bill_pkg_detail');
+
+ eval "use Text::CSV_XS;";
+ die $@ if $@;
+ my $csv = new Text::CSV_XS;
+
+ my @detail =
+ qsearch ({ 'table' => 'cust_bill_pkg_detail',
+ 'hashref' => { 'billpkgnum' => $self->billpkgnum,
+ 'format' => 'C',
+ },
+ 'order_by' => 'ORDER BY detailnum LIMIT 1',
+ });
+ return() unless scalar(@detail);
+ $csv->parse($detail[0]->detail) or return ();
+ $csv->fields;
+}
+
=item desc
Returns a description for this line item. For typical line items, this is the
diff --git a/FS/FS/usage_class.pm b/FS/FS/usage_class.pm
index b64d26a..26520e5 100644
--- a/FS/FS/usage_class.pm
+++ b/FS/FS/usage_class.pm
@@ -127,6 +127,7 @@ my %summary_formats = (
'align' => [ qw( l r r r ) ],
'span' => [ qw( 4 1 1 1 ) ], # unitprices?
'width' => [ qw( 8.2cm 2.5cm 1.4cm 1.6cm ) ], # don't like this
+ 'show' => 1,
},
'simpler' => {
'label' => [ qw( Description Calls Amount ) ],
@@ -138,6 +139,7 @@ my %summary_formats = (
'align' => [ qw( l r r ) ],
'span' => [ qw( 5 1 1 ) ],
'width' => [ qw( 10.7cm 1.4cm 1.6cm ) ], # don't like this
+ 'show' => 1,
},
'usage_simple' => {
'label' => [ qw( Date Time Number Destination Duration Amount ) ],
@@ -147,16 +149,56 @@ my %summary_formats = (
sub { ' ' },
sub { ' ' },
sub { ' ' },
+ sub { my $href = shift; #ugh! making bunk of 'normalization'
+ $href->{subtotal} ? $href->{subtotal} : ' '
+ },
+ ],
+ 'align' => [ qw( l l l l r r ) ],
+ 'span' => [ qw( 1 1 1 1 1 2 ) ], # unitprices?
+ 'width' => [ qw( 4.3cm 1.4cm 2.5cm 2.5cm 1.4cm 1.6cm ) ],# don't like this
+ 'show' => 0,
+ },
+ 'usage_6col' => {
+ 'label' => [ qw( col1 col2 col3 col4 col5 col6 ) ],
+ 'fields' => [
sub { ' ' },
+ sub { ' ' },
+ sub { ' ' },
+ sub { ' ' },
+ sub { ' ' },
+ sub { my $href = shift; #ugh! making bunk of 'normalization'
+ $href->{subtotal} ? $href->{subtotal} : ' '
+ },
],
'align' => [ qw( l l l l r r ) ],
- 'span' => [ qw( 2 1 1 1 1 1 ) ], # unitprices?
+ 'span' => [ qw( 1 1 1 1 1 2 ) ], # unitprices?
'width' => [ qw( 4.3cm 1.4cm 2.5cm 2.5cm 1.4cm 1.6cm ) ],# don't like this
+ 'show' => 0,
+ },
+ 'usage_7col' => {
+ 'label' => [ qw( col1 col2 col3 col4 col5 col6 col7 ) ],
+ 'fields' => [
+ sub { ' ' },
+ sub { ' ' },
+ sub { ' ' },
+ sub { ' ' },
+ sub { ' ' },
+ sub { ' ' },
+ sub { my $href = shift; #ugh! making bunk of 'normalization'
+ $href->{subtotal} ? $href->{subtotal} : ' '
+ },
+ ],
+ 'align' => [ qw( l l l l l r r ) ],
+ 'span' => [ qw( 1 1 1 1 1 1 1 ) ], # unitprices?
+ 'width' => [ qw( 2.9cm 1.4cm 1.4cm 2.5cm 2.5cm 1.4cm 1.6cm ) ],# don't like this
+ 'show' => 0,
},
);
sub summary_formats_labelhash {
- map { $_ => join(',', @{$summary_formats{$_}{label}}) } keys %summary_formats;
+ map { $_ => join(',', @{$summary_formats{$_}{label}}) }
+ grep { $summary_formats{$_}{show} }
+ keys %summary_formats;
}
=item header_generator FORMAT
@@ -173,15 +215,16 @@ my %html_align = (
);
sub _generator_defaults {
- my ( $self, $format ) = ( shift, shift );
- return ( $summary_formats{$self->format}, ' ', ' ', ' ', sub { shift } );
+ my ( $self, $format, %opt ) = @_;
+ my %format = ( %{ $summary_formats{$self->format} }, %opt );
+ return ( \%format, ' ', ' ', ' ', sub { shift } );
}
sub header_generator {
- my ( $self, $format ) = ( shift, shift );
+ my ( $self, $format, %opt ) = @_;
my ( $f, $prefix, $suffix, $separator, $column ) =
- $self->_generator_defaults($format);
+ $self->_generator_defaults($format, %opt);
if ($format eq 'latex') {
$prefix = "\\hline\n\\rule{0pt}{2.5ex}\n\\makebox[1.4cm]{}&\n";
@@ -205,7 +248,7 @@ sub header_generator {
my @args = @_;
my @result = ();
- foreach (my $i = 0; $f->{label}->[$i]; $i++) {
+ foreach (my $i = 0; exists($f->{label}->[$i]); $i++) {
push @result,
&{$column}( map { $f->{$_}->[$i] } qw(label align span width) );
}
@@ -223,10 +266,10 @@ usage_class. FORMAT is either html or latex
=cut
sub description_generator {
- my ( $self, $format ) = ( shift, shift );
+ my ( $self, $format, %opt ) = @_;
my ( $f, $prefix, $suffix, $separator, $column ) =
- $self->_generator_defaults($format);
+ $self->_generator_defaults($format, %opt);
if ($format eq 'latex') {
$prefix = "\\hline\n\\multicolumn{1}{c}{\\rule{0pt}{2.5ex}~} &\n";
@@ -269,13 +312,13 @@ usage_class. FORMAT is either html or latex
=cut
sub total_generator {
- my ( $self, $format ) = ( shift, shift );
+ my ( $self, $format, %opt ) = @_;
# $OUT .= '\FStotaldesc{' . $section->{'description'} . ' Total}' .
# '{' . $section->{'subtotal'} . '}' . "\n";
my ( $f, $prefix, $suffix, $separator, $column ) =
- $self->_generator_defaults($format);
+ $self->_generator_defaults($format, %opt);
my $style = '';
if ($format eq 'latex') {
@@ -328,13 +371,13 @@ usage_class. FORMAT is either html or latex
# total_item and amount vs total_amount -- another array of functions?
sub total_line_generator {
- my ( $self, $format ) = ( shift, shift );
+ my ( $self, $format, %opt ) = @_;
# $OUT .= '\FStotaldesc{' . $line->{'total_item'} . '}' .
# '{' . $line->{'total_amount'} . '}' . "\n";
my ( $f, $prefix, $suffix, $separator, $column ) =
- $self->_generator_defaults($format);
+ $self->_generator_defaults($format, %opt);
my $style = '';
if ($format eq 'latex') {