use FS::Misc qw( generate_ps generate_pdf );
use FS::pkg_category;
use FS::pkg_class;
+use FS::invoice_mode;
use FS::L10N;
$DEBUG = 0;
$date_format_long = $conf->config('date_format_long') || '%b %o, %Y';
} );
-=item print_text HASHREF | [ TIME [ , TEMPLATE [ , OPTION => VALUE ... ] ] ]
+=item conf [ MODE ]
+
+Returns a configuration handle (L<FS::Conf>) set to the customer's locale.
+
+If the "mode" pseudo-field is set on the object, the configuration handle
+will be an L<FS::invoice_conf> for that invoice mode (and the customer's
+locale).
+
+=cut
+
+sub conf {
+ my $self = shift;
+ my $mode = $self->get('mode');
+ if ($self->{_conf} and !defined($mode)) {
+ return $self->{_conf};
+ }
+
+ my $cust_main = $self->cust_main;
+ my $locale = $cust_main ? $cust_main->locale : '';
+ my $conf;
+ if ( $mode ) {
+ if ( ref $mode and $mode->isa('FS::invoice_mode') ) {
+ $mode = $mode->modenum;
+ } elsif ( $mode =~ /\D/ ) {
+ die "invalid invoice mode $mode";
+ }
+ $conf = qsearchs('invoice_conf', { modenum => $mode, locale => $locale });
+ if (!$conf) {
+ $conf = qsearchs('invoice_conf', { modenum => $mode, locale => '' });
+ # it doesn't have a locale, but system conf still might
+ $conf->set('locale' => $locale) if $conf;
+ }
+ }
+ # if $mode is unspecified, or if there is no invoice_conf matching this mode
+ # and locale, then use the system config only (but with the locale)
+ $conf ||= FS::Conf->new({ 'locale' => $locale });
+ # cache it
+ return $self->{_conf} = $conf;
+}
+
+=item print_text OPTIONS
Returns an text invoice, as a list of lines.
-Options can be passed as a hashref (recommended) or as a list of time, template
-and then any key/value pairs for any other options.
+Options can be passed as a hash.
I<time>, if specified, is used to control the printing of overdue messages. The
default is now. It isn't the date of the invoice; that's the `_date' field.
sub print_text {
my $self = shift;
- my( $today, $template, %opt );
+ my %params;
if ( ref($_[0]) ) {
- %opt = %{ shift() };
- $today = delete($opt{'time'}) || '';
- $template = delete($opt{template}) || '';
+ %params = %{ shift() };
} else {
- ( $today, $template, %opt ) = @_;
+ %params = @_;
}
- my %params = ( 'format' => 'template' );
- $params{'time'} = $today if $today;
- $params{'template'} = $template if $template;
- $params{$_} = $opt{$_}
- foreach grep $opt{$_}, qw( unsquelch_cdr notice_name );
+ $params{'format'} = 'template'; # for some reason
$self->print_generic( %params );
}
-=item print_latex HASHREF | [ TIME [ , TEMPLATE [ , OPTION => VALUE ... ] ] ]
+=item print_latex HASHREF
Internal method - returns a filename of a filled-in LaTeX template for this
invoice (Note: add ".tex" to get the actual filename), and a filename of
See print_ps and print_pdf for methods that return PostScript and PDF output.
-Options can be passed as a hashref (recommended) or as a list of time, template
-and then any key/value pairs for any other options.
+Options can be passed as a hash.
I<time>, if specified, is used to control the printing of overdue messages. The
default is now. It isn't the date of the invoice; that's the `_date' field.
It is specified as a UNIX timestamp; see L<perlfunc/"time">. Also see
L<Time::Local> and L<Date::Parse> for conversion functions.
-I<template>, if specified, is the name of a suffix for alternate invoices.
+I<template>, if specified, is the name of a suffix for alternate invoices.
+This is strongly deprecated; see L<FS::invoice_conf> for the right way to
+customize invoice templates for different purposes.
I<notice_name>, if specified, overrides "Invoice" as the name of the sent document (templates from 10/2009 or newer required)
sub print_latex {
my $self = shift;
- my $conf = $self->conf;
- my( $today, $template, %opt );
+ my %params;
+
if ( ref($_[0]) ) {
- %opt = %{ shift() };
- $today = delete($opt{'time'}) || '';
- $template = delete($opt{template}) || '';
+ %params = %{ shift() };
} else {
- ( $today, $template, %opt ) = @_;
+ %params = @_;
}
- my %params = ( 'format' => 'latex' );
- $params{'time'} = $today if $today;
- $params{'template'} = $template if $template;
- $params{$_} = $opt{$_}
- foreach grep $opt{$_}, qw( unsquelch_cdr notice_name no_date no_number );
+ $params{'format'} = 'latex';
+ my $conf = $self->conf;
+ # this needs to go away
+ my $template = $params{'template'};
+ # and this especially
$template ||= $self->_agent_template
if $self->can('_agent_template');
Optional options include
-template - a value used as a suffix for a configuration template
+template - a value used as a suffix for a configuration template. Please
+don't use this.
time - a value used to control the printing of overdue messages. The
default is now. It isn't the date of the invoice; that's the `_date' field.
sub print_generic {
my( $self, %params ) = @_;
my $conf = $self->conf;
+
my $today = $params{today} ? $params{today} : time;
warn "$me print_generic called on $self with suffix $params{template}\n"
if $DEBUG;
unless $cust_main->payname
&& $cust_main->payby !~ /^(CARD|DCRD|CHEK|DCHK)$/;
+ my $locale = $params{'locale'} || $cust_main->locale;
+
my %delimiters = ( 'latex' => [ '[@--', '--@]' ],
'html' => [ '<%=', '%>' ],
'template' => [ '{', '}' ],
warn "$me print_generic creating template\n"
if $DEBUG > 1;
+ # set the notice name here, and nowhere else.
+ my $notice_name = $params{notice_name}
+ || $conf->config('notice_name')
+ || $self->notice_name;
+
#create the template
my $template = $params{template} ? $params{template} : $self->_agent_template;
my $templatefile = $self->template_conf. $format;
$templatefile .= "_$template"
if length($template) && $conf->exists($templatefile."_$template");
+
+ # the base template
my @invoice_template = map "$_\n", $conf->config($templatefile)
or die "cannot load config data $templatefile";
# generate template variables
my $returnaddress;
+
if (
defined( $conf->config_orbase( "invoice_${format}returnaddress",
$template
'today' => time2str($date_format_long, $today),
'terms' => $self->terms,
'template' => $template, #params{'template'},
- 'notice_name' => ($params{'notice_name'} || $self->notice_name),#escape_function?
+ 'notice_name' => $notice_name, # escape?
'current_charges' => sprintf("%.2f", $self->charged),
'duedate' => $self->due_date2str($rdate_format), #date_format?
);
#localization
- my $lh = FS::L10N->get_handle( $params{'locale'} || $cust_main->locale );
+ my $lh = FS::L10N->get_handle( $locale );
$invoice_data{'emt'} = sub { &$escape_function($self->mt(@_)) };
my %info = FS::Locales->locale_info($cust_main->locale || 'en_US');
# eval to avoid death for unimplemented languages
# summary formats
$invoice_data{'last_bill'} = {};
- # returns the last unpaid bill, not the last bill
- #my $last_bill = $pr_cust_bill[-1];
-
if ( $self->custnum && $self->invnum ) {
- # THIS returns the customer's last bill before this one
- my $last_bill = qsearchs({
- 'table' => 'cust_bill',
- 'hashref' => { 'custnum' => $self->custnum,
- 'invnum' => { op => '<', value => $self->invnum },
- },
- 'order_by' => ' ORDER BY invnum DESC LIMIT 1'
- });
- if ( $last_bill ) {
+ if ( $self->previous_bill ) {
+ my $last_bill = $self->previous_bill;
$invoice_data{'last_bill'} = {
'_date' => $last_bill->_date, #unformatted
- # all we need for now
};
my (@payments, @credits);
# for formats that itemize previous payments
my $taxtotal = 0;
my $tax_section = { 'description' => $self->mt('Taxes, Surcharges, and Fees'),
'subtotal' => $taxtotal, # adjusted below
+ 'tax_section' => 1,
};
my $tax_weight = _pkg_category($tax_section->{description})
? _pkg_category($tax_section->{description})->weight
foreach my $section (@sections, @$late_sections) {
- warn "$me adding section \n". Dumper($section)
- if $DEBUG > 1;
-
# begin some normalization
$section->{'subtotal'} = $section->{'amount'}
if $multisection
$adjust_section->{'pretotal'} = $self->mt('New charges total').' '.
$other_money_char. sprintf('%.2f', $self->charged );
}
- }else{
+ } else {
push @total_items, $total;
}
push @buf,['','-----------'];
my %params;
if ( ref($_[0]) ) {
%params = %{ shift() };
- }else{
- $params{'time'} = shift;
- $params{'template'} = shift;
- $params{'cid'} = shift;
+ } else {
+ %params = @_;
}
-
$params{'format'} = 'html';
$self->print_generic( %params );
if $DEBUG > 1;
my $is_summary = $display->summary;
- my $description = ($is_summary && $type && $type eq 'U')
- ? "Usage charges" : $desc;
+ my $description = $desc;
+ if ( $type eq 'U' and ($is_summary or $cust_bill_pkg->hidden) ) {
+ $description = $self->mt('Usage charges');
+ }
my $part_pkg = $cust_pkg->part_pkg;
if $DEBUG > 1;
my @svc_labels = map &{$escape_function}($_),
- $cust_pkg->h_labels_short($self->_date, undef, 'I');
+ $cust_pkg->h_labels_short(@dates, 'I');
push @d, @svc_labels
unless $cust_bill_pkg->pkgpart_override; #don't redisplay services
$svc_label = $svc_labels[0];
warn "$me _items_cust_bill_pkg adding usage\n"
if $DEBUG > 1;
- if ( $cust_bill_pkg->hidden ) {
+ if ( $cust_bill_pkg->hidden and defined($u) ) {
+ # if this is a hidden package and there's already a usage
+ # line for the bundle, add this package's total amount and
+ # usage details to it
$u->{amount} += $amount;
$u->{unit_amount} += $unit_amount,
push @{ $u->{ext_description} }, @d;
- } else {
+ } elsif ( $amount ) {
+ # create a new usage line
$u = {
description => $description,
pkgpart => $pkgpart,
%item_dates,
ext_description => \@d,
};
- }
+ } # else this has no usage, so don't create a usage section
}
} # recurring or usage with recurring charge