cust_pay_batch
cust_bill_pay_batch
cust_bill_pkg
+ cust_bill_batch
)) {
foreach my $linked ( $self->$table() ) {
'table' => 'cust_bill_pay_pkg',
'addl_from' => ' LEFT JOIN cust_bill_pay USING ( billpaynum ) '.
' LEFT JOIN cust_bill_pkg USING ( billpkgnum ) ',
- 'hashref' => { 'invnum' => $self->invnum,
- 'pkgnum' => $pkgnum,
- },
+ 'extra_sql' => ' WHERE cust_bill_pkg.invnum = '. $self->invnum.
+ " AND cust_bill_pkg.pkgnum = $pkgnum",
});
}
'table' => 'cust_credit_bill_pkg',
'addl_from' => ' LEFT JOIN cust_credit_bill USING ( creditbillnum ) '.
' LEFT JOIN cust_bill_pkg USING ( billpkgnum ) ',
- 'hashref' => { 'invnum' => $self->invnum,
- 'pkgnum' => $pkgnum,
- },
+ 'extra_sql' => ' WHERE cust_bill_pkg.invnum = '. $self->invnum.
+ " AND cust_bill_pkg.pkgnum = $pkgnum",
});
}
+=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.
#invoice from info
'company_name' => scalar( $conf->config('company_name', $agentnum) ),
'company_address' => join("\n", $conf->config('company_address', $agentnum) ). "\n",
+ 'company_phonenum'=> scalar( $conf->config('company_phonenum', $agentnum) ),
'returnaddress' => $returnaddress,
'agent' => &$escape_function($cust_main->agent->agent),
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' => '' };
}
}
}
-
+
if ( @pr_cust_bill && !$conf->exists('disable_previous_balance') ) {
push @buf, ['','-----------'];
push @buf, [ 'Total Previous Balance',
if $DEBUG > 1;
my ($didsummary,$minutes) = $self->_did_summary;
- my $didsummary_desc = 'DID Activity Summary (Past 30 days)';
+ my $didsummary_desc = 'DID Activity Summary (since last invoice)';
push @detail_items,
{ 'description' => $didsummary_desc,
'ext_description' => [ $didsummary, $minutes ],
my ($file, $logofile, $barcodefile) = $self->print_latex(@_);
my $ps = generate_ps($file);
unlink($logofile);
- unlink($barcodefile);
+ unlink($barcodefile) if $barcodefile;
$ps;
}
my ($file, $logofile, $barcodefile) = $self->print_latex(@_);
my $pdf = generate_pdf($file);
unlink($logofile);
- unlink($barcodefile);
+ unlink($barcodefile) if $barcodefile;
$pdf;
}
}
} @sections;
push @early, @$extra_sections if $extra_sections;
-
+
sort { $a->{sort_weight} <=> $b->{sort_weight} } @early;
}
sub _did_summary {
my $self = shift;
my $end = $self->_date;
- my $start = $end - 2592000; # 30 days
+
+ # start at date of previous invoice + 1 second or 0 if no previous invoice
+ my $start = $self->scalar_sql("SELECT max(_date) FROM cust_bill WHERE custnum = ? and invnum != ?",$self->custnum,$self->invnum);
+ $start = 0 if !$start;
+ $start++;
+
my $cust_main = $self->cust_main;
my @pkgs = $cust_main->all_pkgs;
my($num_activated,$num_deactivated,$num_portedin,$num_portedout,$minutes)
"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;
ext_description => \@d,
};
}
-
}
} # recurring or usage with recurring charge