From dc3217c61d6a62a8e599d8804e05ba45b3224c7e Mon Sep 17 00:00:00 2001 From: jeff Date: Fri, 16 May 2008 19:26:40 +0000 Subject: [PATCH] typeset CDRs into 5 columns on invoices --- FS/FS/Schema.pm | 1 + FS/FS/cdr.pm | 8 ++++++ FS/FS/cust_bill.pm | 16 ++++++++---- FS/FS/cust_bill_pkg.pm | 57 ++++++++++++++++++++++++++++++++++++++----- FS/FS/cust_bill_pkg_detail.pm | 1 + FS/FS/part_pkg/voip_cdr.pm | 20 +++++++-------- conf/invoice_html | 16 ++++++------ conf/invoice_latex | 13 +++++++--- 8 files changed, 100 insertions(+), 32 deletions(-) diff --git a/FS/FS/Schema.pm b/FS/FS/Schema.pm index f8dd38b8c..457e5c80d 100644 --- a/FS/FS/Schema.pm +++ b/FS/FS/Schema.pm @@ -499,6 +499,7 @@ sub tables_hashref { 'detailnum', 'serial', '', '', '', '', 'pkgnum', 'int', '', '', '', '', 'invnum', 'int', '', '', '', '', + 'format', 'char', 'NULL', 1, '', '', 'detail', 'varchar', '', $char_d, '', '', ], 'primary_key' => 'detailnum', diff --git a/FS/FS/cdr.pm b/FS/FS/cdr.pm index c10eec053..29bbe0e99 100644 --- a/FS/FS/cdr.pm +++ b/FS/FS/cdr.pm @@ -408,6 +408,14 @@ my %export_formats = ( sub { shift->rated_price ? 'Y' : 'N' }, #RATED '', #OTHER_INFO ], + 'voxlinesystems' => [ + sub { time2str('%D', shift->calldate_unix ) }, #DATE + sub { time2str('%T', shift->calldate_unix ) }, #TIME + 'userfield', #USER + 'dst', #NUMBER_DIALED + sub { sprintf('%.2fm', shift->billsec / 60 ) }, #DURATION + sub { sprintf('%.3f', shift->upstream_price ) }, #PRICE + ], ); sub downstream_csv { diff --git a/FS/FS/cust_bill.pm b/FS/FS/cust_bill.pm index f47081317..9b7c4add7 100644 --- a/FS/FS/cust_bill.pm +++ b/FS/FS/cust_bill.pm @@ -2000,6 +2000,7 @@ sub print_generic { my %options = (); $options{'section'} = $section if $multisection; + $options{'format'} = $format; foreach my $line_item ( $self->_items_pkg(%options) ) { my $detail = { @@ -2010,9 +2011,7 @@ sub print_generic { $detail->{'section'} = $section; $detail->{'description'} = &$escape_function($line_item->{'description'}); if ( exists $line_item->{'ext_description'} ) { - @{$detail->{'ext_description'}} = map { - &$escape_function($_); - } @{$line_item->{'ext_description'}}; + @{$detail->{'ext_description'}} = @{$line_item->{'ext_description'}}; } { my $money = $old_latex ? '' : $money_char; @@ -2528,6 +2527,9 @@ sub _items_tax { sub _items_cust_bill_pkg { my $self = shift; my $cust_bill_pkg = shift; + my %opt = @_; + my $format = $opt{format} || ''; + my $escape_function = $opt{escape_function} || sub { shift }; my @b = (); foreach my $cust_bill_pkg ( @$cust_bill_pkg ) { @@ -2542,7 +2544,10 @@ sub _items_cust_bill_pkg { my $description = $desc; $description .= ' Setup' if $cust_bill_pkg->recur != 0; my @d = $cust_pkg->h_labels_short($self->_date); - push @d, $cust_bill_pkg->details if $cust_bill_pkg->recur == 0; + push @d, $cust_bill_pkg->details( 'format' => $format, + 'escape_function' => $escape_function, + ) + if $cust_bill_pkg->recur == 0; push @b, { description => $description, #pkgpart => $part_pkg->pkgpart, @@ -2569,7 +2574,8 @@ sub _items_cust_bill_pkg { [ $cust_pkg->h_labels_short( $self->_date ), #$cust_bill_pkg->edate, #$cust_bill_pkg->sdate), - $cust_bill_pkg->details, + $cust_bill_pkg->details( 'format' => $format, + 'escape_function' => $escape_function), ], }; } diff --git a/FS/FS/cust_bill_pkg.pm b/FS/FS/cust_bill_pkg.pm index 1cb982681..5d60311cf 100644 --- a/FS/FS/cust_bill_pkg.pm +++ b/FS/FS/cust_bill_pkg.pm @@ -112,7 +112,8 @@ sub insert { my $cust_bill_pkg_detail = new FS::cust_bill_pkg_detail { 'pkgnum' => $self->pkgnum, 'invnum' => $self->invnum, - 'detail' => $detail, + 'format' => (ref($detail) ? $detail->[0] : '' ), + 'detail' => (ref($detail) ? $detail->[1] : $detail ), }; $error = $cust_bill_pkg_detail->insert; if ( $error ) { @@ -220,18 +221,62 @@ sub cust_bill { qsearchs( 'cust_bill', { 'invnum' => $self->invnum } ); } -=item details +=item details [ OPTION => VALUE ... ] Returns an array of detail information for the invoice line item. +Currently available options are: I I + +If I is set to html or latex then the array members are improved +for tabular appearance in those environments if possible. + +If I is set then the array members are processed by this +function before being returned. + =cut sub details { - my $self = shift; + my ( $self, %opt ) = @_; + my $format = $opt{format} || ''; + my $escape_function = $opt{escape_function} || sub { shift }; return () unless defined dbdef->table('cust_bill_pkg_detail'); - map { $_->detail } - qsearch ( 'cust_bill_pkg_detail', { 'pkgnum' => $self->pkgnum, - 'invnum' => $self->invnum, } ); + + eval "use Text::CSV_XS;"; + die $@ if $@; + my $csv = new Text::CSV_XS; + + my $format_sub = sub { my $detail = shift; + $csv->parse($detail) or return "can't parse $detail"; + join(' - ', map { &$escape_function($_) } + $csv->fields + ); + }; + + $format_sub = sub { my $detail = shift; + $csv->parse($detail) or return "can't parse $detail"; + join('', map { &$escape_function($_) } + $csv->fields + ); + } + if $format eq 'html'; + + $format_sub = sub { my $detail = shift; + $csv->parse($detail) or return "can't parse $detail"; + join(' & ', map { &$escape_function($_) } $csv->fields ); + } + if $format eq 'latex'; + + map { ( $_->format eq 'C' + ? &{$format_sub}( $_->detail ) + : &{$escape_function}( $_->detail ) + ) + } + qsearch ({ 'table' => 'cust_bill_pkg_detail', + 'hashref' => { 'pkgnum' => $self->pkgnum, + 'invnum' => $self->invnum, + }, + 'order_by' => 'ORDER BY detailnum', + }); #qsearch ( 'cust_bill_pkg_detail', { 'lineitemnum' => $self->lineitemnum }); } diff --git a/FS/FS/cust_bill_pkg_detail.pm b/FS/FS/cust_bill_pkg_detail.pm index 4156816c8..a69998a42 100644 --- a/FS/FS/cust_bill_pkg_detail.pm +++ b/FS/FS/cust_bill_pkg_detail.pm @@ -104,6 +104,7 @@ sub check { $self->ut_numbern('detailnum') || $self->ut_foreign_key('pkgnum', 'cust_pkg', 'pkgnum') || $self->ut_foreign_key('invnum', 'cust_bill', 'invnum') + || $self->ut_enum('format', [ '', 'C' ] ) || $self->ut_text('detail') || $self->SUPER::check ; diff --git a/FS/FS/part_pkg/voip_cdr.pm b/FS/FS/part_pkg/voip_cdr.pm index c4827c9c5..0f25e15d4 100644 --- a/FS/FS/part_pkg/voip_cdr.pm +++ b/FS/FS/part_pkg/voip_cdr.pm @@ -292,15 +292,7 @@ sub calc_recur { $charge = sprintf('%.3f', $cdr->upstream_price); $charges += $charge; - @call_details = ( - #time2str("%Y %b %d - %r", $cdr->calldate_unix ), - time2str("%c", $cdr->calldate_unix), #XXX this should probably be a config option dropdown so they can select US vs- rest of world dates or whatnot - sprintf('%.2f', $cdr->billsec / 60 ).'m', - '$'.$charge, #XXX $money_char - #$pretty_destnum, - $cdr->userfield, #$rate_region->regionname, - $cdr->dst, - ); + @call_details = ( $cdr->downstream_csv( 'format' => 'voxlinesystems' )); } else { die "don't know how to rate CDRs using method: ". @@ -363,7 +355,12 @@ sub calc_recur { } if ( $charge > 0 ) { - my $call_details = join(' - ', @call_details ); + my $call_details; + if ( $self->option('rating_method') eq 'upstream_simple' ) { + $call_details = [ 'C', $call_details[0] ]; + }else{ + $call_details = join(' - ', @call_details ); + } warn " adding details on charge to invoice: $call_details" if $DEBUG; push @$details, $call_details; #\@call_details, @@ -382,6 +379,9 @@ sub calc_recur { } # $cdr + unshift @$details, [ 'C', "Date,Time,Name,Destination,Duration,Price" ] + if (@$details && $self->option('rating_method') eq 'upstream_simple' ); + } # $cust_svc if ( $spool_cdr && length($downstream_cdr) ) { diff --git a/conf/invoice_html b/conf/invoice_html index 9d97243e4..14b25c671 100644 --- a/conf/invoice_html +++ b/conf/invoice_html @@ -106,13 +106,15 @@ ''. $line->{'amount'}. ''. '' ; - foreach my $ext_desc ( @{$line->{'ext_description'} } ) { - $OUT .= - ''. - ''. - '- '. $ext_desc. ''. - ''. - '' + if ( @{$line->{'ext_description'} } ) { + $OUT .= ''; + foreach my $ext_desc ( @{$line->{'ext_description'} } ) { + $OUT .= + ''. + ''. + '' + } + $OUT .= '
- '. $ext_desc. '
'; } } diff --git a/conf/invoice_latex b/conf/invoice_latex index 6a81c4c2e..e43fc3eb0 100644 --- a/conf/invoice_latex +++ b/conf/invoice_latex @@ -242,10 +242,15 @@ Terms: [@-- $terms --@]\\ $OUT .= '\FSdesc{' . $line->{'ref'} . '}{' . $line->{'description'} . '}' . '{' . $line->{'amount'} . "}${rowbreak}\n"; - foreach my $ext_desc (@$ext_description) { - $ext_desc = substr($ext_desc, 0, 80) . '...' - if (length($ext_desc) > 80); - $OUT .= '\FSextdesc{' . $ext_desc . '}' . "${rowbreak}\n"; + if (@$ext_description) { + $OUT .= '\multicolumn{1}{l}{\rule{0pt}{1.0ex}} &'; + $OUT .= '\multicolumn{2}{l}{\begin{tabular}{lllll}'; %%cheating at 5 + foreach my $ext_desc (@$ext_description) { + $ext_desc = substr($ext_desc, 0, 80) . '...' + if (length($ext_desc) > 80); + $OUT .= '\small{' . $ext_desc . '}' . "\\\\${rowbreak}\n"; + } + $OUT .="\\end{tabular}}\\\\${rowbreak}\n"; } } -- 2.11.0