cust_pay_batch
cust_bill_pay_batch
cust_bill_pkg
+ cust_bill_batch
)) {
foreach my $linked ( $self->$table() ) {
}
+=item cust_bill_batch
+
+Returns all invoice batch records (L<FS::cust_bill_batch>) for this invoice.
+
+=cut
+
+sub cust_bill_batch {
+ my $self = shift;
+ qsearch('cust_bill_batch', { 'invnum' => $self->invnum });
+}
+
=item tax
Returns the tax amount (see L<FS::cust_bill_pkg>) for this invoice.
sub batch_invoice {
my ($self, $opt) = @_;
- my $batch = FS::bill_batch->get_open_batch;
+ my $bill_batch = $self->get_open_bill_batch;
my $cust_bill_batch = FS::cust_bill_batch->new({
- batchnum => $batch->batchnum,
+ batchnum => $bill_batch->batchnum,
invnum => $self->invnum,
});
return $cust_bill_batch->insert($opt);
}
+=item get_open_batch
+
+Returns the currently open batch as an FS::bill_batch object, creating a new
+one if necessary. (A per-agent batch if invoice_print_pdf-spoolagent is
+enabled)
+
+=cut
+
+sub get_open_bill_batch {
+ my $self = shift;
+ my $hashref = { status => 'O' };
+ $hashref->{'agentnum'} = $conf->exists('invoice_print_pdf-spoolagent')
+ ? $self->cust_main->agentnum
+ : '';
+ my $batch = qsearchs('bill_batch', $hashref);
+ return $batch if $batch;
+ $batch = FS::bill_batch->new($hashref);
+ my $error = $batch->insert;
+ die $error if $error;
+ return $batch;
+}
+
=item ftp_invoice [ TEMPLATENAME ]
Sends this invoice data via FTP.
$params{'time'} = $today if $today;
$params{'template'} = $template if $template;
$params{$_} = $opt{$_}
- foreach grep $opt{$_}, qw( unsquealch_cdr notice_name );
+ foreach grep $opt{$_}, qw( unsquelch_cdr notice_name );
$self->print_generic( %params );
}
$params{'time'} = $today if $today;
$params{'template'} = $template if $template;
$params{$_} = $opt{$_}
- foreach grep $opt{$_}, qw( unsquealch_cdr notice_name );
+ foreach grep $opt{$_}, qw( unsquelch_cdr notice_name );
$template ||= $self->_agent_template;
push @{$late_sections}, @$phone_sections;
push @detail_items, @$phone_lines;
}
+ if ($conf->exists('voip-cust_accountcode_cdr') && $cust_main->accountcode_cdr) {
+ my ($accountcode_section, $accountcode_lines) =
+ $self->_items_accountcode_cdr($escape_function_nonbsp,$format);
+ if ( scalar(@$accountcode_lines) ) {
+ push @{$late_sections}, $accountcode_section;
+ push @detail_items, @$accountcode_lines;
+ }
+ }
}else{
push @sections, { 'description' => '', 'subtotal' => '' };
}
push @detail_items,
{ 'description' => $didsummary_desc,
'ext_description' => [ $didsummary, $minutes ],
- }
- if !$multisection;
+ };
}
foreach my $section (@sections, @$late_sections) {
my %classnums = ();
my %lines = ();
+ my $maxlength = $conf->config('cust_bill-latex_lineitem_maxlength') || 50;
+
my %usage_class = map { $_->classnum => $_ } qsearch( 'usage_class', {} );
foreach my $cust_bill_pkg ( $self->cust_bill_pkg ) {
next unless $cust_bill_pkg->pkgnum > 0;
my $desc = $detail->regionname;
my $description = $desc;
- $description = substr($desc, 0, 50). '...'
- if $format eq 'latex' && length($desc) > 50;
+ $description = substr($desc, 0, $maxlength). '...'
+ if $format eq 'latex' && length($desc) > $maxlength;
$lines{$section}{$desc} ||= {
description => &{$escape}($description),
my $inserted = $h_cust_svc->date_inserted;
my $deleted = $h_cust_svc->date_deleted;
- my $phone_inserted = $h_cust_svc->h_svc_x($inserted);
+ my $phone_inserted = $h_cust_svc->h_svc_x($inserted+5);
my $phone_deleted;
$phone_deleted = $h_cust_svc->h_svc_x($deleted) if $deleted;
}
# increment usage minutes
- my @cdrs = $phone_inserted->get_cdrs('begin'=>$start,'end'=>$end);
- foreach my $cdr ( @cdrs ) {
- $minutes += $cdr->billsec/60;
- }
+ if ( $phone_inserted ) {
+ my @cdrs = $phone_inserted->get_cdrs('begin'=>$start,'end'=>$end,'billsec_sum'=>1);
+ $minutes = $cdrs[0]->billsec_sum if scalar(@cdrs) == 1;
+ }
+ else {
+ warn "WARNING: no matching h_svc_phone insert record for insert time $inserted, svcnum " . $h_cust_svc->svcnum;
+ }
# don't look at this service again
push @seen, $h_cust_svc->svcnum;
"Total Minutes: $minutes");
}
+sub _items_accountcode_cdr {
+ my $self = shift;
+ my $escape = shift;
+ my $format = shift;
+
+ my $section = { 'amount' => 0,
+ 'calls' => 0,
+ 'duration' => 0,
+ 'sort_weight' => '',
+ 'phonenum' => '',
+ 'description' => 'Usage by Account Code',
+ 'post_total' => '',
+ 'summarized' => '',
+ 'header' => '',
+ };
+ my @lines;
+ my %accountcodes = ();
+
+ 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);
+ $section->{'header'} = join(',',@header);
+
+ foreach my $detail ( $cust_bill_pkg->cust_bill_pkg_detail ) {
+
+ $section->{'header'} = $detail->formatted('format' => $format)
+ if($detail->detail eq $section->{'header'});
+
+ my $accountcode = $detail->accountcode;
+ next unless $accountcode;
+
+ my $amount = $detail->amount;
+ next unless $amount && $amount > 0;
+
+ $accountcodes{$accountcode} ||= {
+ description => $accountcode,
+ pkgnum => '',
+ ref => '',
+ amount => 0,
+ calls => 0,
+ duration => 0,
+ quantity => '',
+ product_code => 'N/A',
+ section => $section,
+ ext_description => [],
+ };
+
+ $section->{'amount'} += $amount;
+ $accountcodes{$accountcode}{'amount'} += $amount;
+ $accountcodes{$accountcode}{calls}++;
+ $accountcodes{$accountcode}{duration} += $detail->duration;
+ push @{$accountcodes{$accountcode}{ext_description}},
+ $detail->formatted('format' => $format);
+ }
+ }
+
+ foreach my $l ( values %accountcodes ) {
+ $l->{amount} = sprintf( "%.2f", $l->{amount} );
+ unshift @{$l->{ext_description}}, $section->{'header'};
+ push @lines, $l;
+ }
+
+ my @sorted_lines = sort { $a->{'description'} <=> $b->{'description'} } @lines;
+
+ return ($section,\@sorted_lines);
+}
+
sub _items_svc_phone_sections {
my $self = shift;
my $escape = shift;
my %classnums = ();
my %lines = ();
+ my $maxlength = $conf->config('cust_bill-latex_lineitem_maxlength') || 50;
+
my %usage_class = map { $_->classnum => $_ } qsearch( 'usage_class', {} );
$usage_class{''} ||= new FS::usage_class { 'classname' => '', 'weight' => 0 };
my $desc = $detail->regionname;
my $description = $desc;
- $description = substr($desc, 0, 50). '...'
- if $format eq 'latex' && length($desc) > 50;
+ $description = substr($desc, 0, $maxlength). '...'
+ if $format eq 'latex' && length($desc) > $maxlength;
$lines{$phonenum}{$desc} ||= {
description => &{$escape}($description),
my $multisection = $opt{multisection} || '';
my $discount_show_always = 0;
+ my $maxlength = $conf->config('cust_bill-latex_lineitem_maxlength') || 50;
+
my @b = ();
my ($s, $r, $u) = ( undef, undef, undef );
foreach my $cust_bill_pkg ( @$cust_bill_pkgs )
{
- warn "$me _items_cust_bill_pkg considering cust_bill_pkg $cust_bill_pkg\n"
+ warn "$me _items_cust_bill_pkg considering cust_bill_pkg ".
+ $cust_bill_pkg->billpkgnum. ", pkgnum ". $cust_bill_pkg->pkgnum. "\n"
if $DEBUG > 1;
- $discount_show_always = ($cust_bill_pkg->cust_bill_pkg_discount
- && $conf->exists('discount-show-always'));
-
- foreach ( $s, $r, ($opt{skip_usage} ? () : $u ) ) {
- if ( $_ && !$cust_bill_pkg->hidden ) {
- $_->{amount} = sprintf( "%.2f", $_->{amount} ),
- $_->{amount} =~ s/^\-0\.00$/0.00/;
- $_->{unit_amount} = sprintf( "%.2f", $_->{unit_amount} ),
- push @b, { %$_ }
- unless ( $_->{amount} == 0 && !$discount_show_always );
- $_ = undef;
- }
- }
-
foreach my $display ( grep { defined($section)
? $_->section eq $section
: 1
my $type = $display->type;
my $desc = $cust_bill_pkg->desc;
- $desc = substr($desc, 0, 50). '...'
- if $format eq 'latex' && length($desc) > 50;
+ $desc = substr($desc, 0, $maxlength). '...'
+ if $format eq 'latex' && length($desc) > $maxlength;
my %details_opt = ( 'format' => $format,
'escape_function' => $escape_function,
my $cust_pkg = $cust_bill_pkg->cust_pkg;
- if ( $cust_bill_pkg->setup != 0 && (!$type || $type eq 'S') ) {
+ if ( (!$type || $type eq 'S')
+ && ( $cust_bill_pkg->setup != 0
+ || $cust_bill_pkg->setup_show_zero
+ )
+ )
+ {
warn "$me _items_cust_bill_pkg adding setup\n"
if $DEBUG > 1;
my $description = $desc;
- $description .= ' Setup' if $cust_bill_pkg->recur != 0;
+ $description .= ' Setup'
+ if $cust_bill_pkg->recur != 0
+ || $discount_show_always
+ || $cust_bill_pkg->recur_show_zero;
my @d = ();
unless ( $cust_pkg->part_pkg->hide_svc_detail
if ( $multilocation ) {
my $loc = $cust_pkg->location_label;
- $loc = substr($loc, 0, 50). '...'
- if $format eq 'latex' && length($loc) > 50;
+ $loc = substr($loc, 0, $maxlength). '...'
+ if $format eq 'latex' && length($loc) > $maxlength;
push @d, &{$escape_function}($loc);
}
push @{ $s->{ext_description} }, @d;
} else {
$s = {
+ _is_setup => 1,
description => $description,
#pkgpart => $part_pkg->pkgpart,
pkgnum => $cust_bill_pkg->pkgnum,
}
- if ( ( $cust_bill_pkg->recur != 0 || $cust_bill_pkg->setup == 0 ||
- ($discount_show_always && $cust_bill_pkg->recur == 0) ) &&
- ( !$type || $type eq 'R' || $type eq 'U' )
+ if ( ( !$type || $type eq 'R' || $type eq 'U' )
+ && (
+ $cust_bill_pkg->recur != 0
+ || $cust_bill_pkg->setup == 0
+ || $discount_show_always
+ || $cust_bill_pkg->recur_show_zero
+ )
)
{
$description .= " (" . time2str($date_format, $cust_bill_pkg->sdate).
" - ". time2str($date_format, $cust_bill_pkg->edate).
")"
- unless $conf->exists('disable_line_item_date_ranges');
+ unless $conf->exists('disable_line_item_date_ranges')
+ || $cust_pkg->part_pkg->option('disable_line_item_date_ranges',1);
my @d = ();
if ( $multilocation ) {
my $loc = $cust_pkg->location_label;
- $loc = substr($loc, 0, 50). '...'
- if $format eq 'latex' && length($loc) > 50;
+ $loc = substr($loc, 0, $maxlength). '...'
+ if $format eq 'latex' && length($loc) > $maxlength;
push @d, &{$escape_function}($loc);
}
ext_description => \@d,
};
}
-
}
} # recurring or usage with recurring charge
}
+ $discount_show_always = ($cust_bill_pkg->cust_bill_pkg_discount
+ && $conf->exists('discount-show-always'));
+
+ foreach ( $s, $r, ($opt{skip_usage} ? () : $u ) ) {
+ if ( $_ && !$cust_bill_pkg->hidden ) {
+ $_->{amount} = sprintf( "%.2f", $_->{amount} ),
+ $_->{amount} =~ s/^\-0\.00$/0.00/;
+ $_->{unit_amount} = sprintf( "%.2f", $_->{unit_amount} ),
+ push @b, { %$_ }
+ if $_->{amount} != 0
+ || $discount_show_always
+ || ( ! $_->{_is_setup} && $cust_bill_pkg->recur_show_zero )
+ || ( $_->{_is_setup} && $cust_bill_pkg->setup_show_zero )
+ ;
+ $_ = undef;
+ }
+ }
+
}
+ #foreach ( $s, $r, ($opt{skip_usage} ? () : $u ) ) {
+ # if ( $_ ) {
+ # $_->{amount} = sprintf( "%.2f", $_->{amount} ),
+ # $_->{amount} =~ s/^\-0\.00$/0.00/;
+ # $_->{unit_amount} = sprintf( "%.2f", $_->{unit_amount} ),
+ # push @b, { %$_ }
+ # if $_->{amount} != 0
+ # || $discount_show_always
+ # }
+ #}
+
warn "$me _items_cust_bill_pkg done considering cust_bill_pkgs\n"
if $DEBUG > 1;
- foreach ( $s, $r, ($opt{skip_usage} ? () : $u ) ) {
- if ( $_ ) {
- $_->{amount} = sprintf( "%.2f", $_->{amount} ),
- $_->{amount} =~ s/^\-0\.00$/0.00/;
- $_->{unit_amount} = sprintf( "%.2f", $_->{unit_amount} ),
- push @b, { %$_ }
- unless ( $_->{amount} == 0 && !$discount_show_always );
- }
- }
-
@b;
}