- my($pkg, $setup, $recur, $sdate, $edate);
- if ( $cust_bill_pkg->pkgnum ) {
-
- ($pkg, $setup, $recur, $sdate, $edate) = (
- $cust_bill_pkg->part_pkg->pkg,
- ( $cust_bill_pkg->setup != 0
- ? sprintf("%.2f", $cust_bill_pkg->setup )
- : '' ),
- ( $cust_bill_pkg->recur != 0
- ? sprintf("%.2f", $cust_bill_pkg->recur )
- : '' ),
- ( $cust_bill_pkg->sdate
- ? time2str("%x", $cust_bill_pkg->sdate)
- : '' ),
- ($cust_bill_pkg->edate
- ?time2str("%x", $cust_bill_pkg->edate)
- : '' ),
- );
-
- } else { #pkgnum tax
- next unless $cust_bill_pkg->setup != 0;
- $pkg = $cust_bill_pkg->desc;
- $setup = sprintf('%10.2f', $cust_bill_pkg->setup );
- ( $sdate, $edate ) = ( '', '' );
- }
-
- $csv->combine(
- 'cust_bill_pkg',
- $self->invnum,
- ( map { '' } (1..11) ),
- ($pkg, $setup, $recur, $sdate, $edate)
- ) or die "can't create csv";
-
- $detail .= $csv->string. "\n";
-
- }
-
- }
-
- ( $header, $detail );
-
-}
-
-=item comp
-
-Pays this invoice with a compliemntary payment. If there is an error,
-returns the error, otherwise returns false.
-
-=cut
-
-sub comp {
- my $self = shift;
- my $cust_pay = new FS::cust_pay ( {
- 'invnum' => $self->invnum,
- 'paid' => $self->owed,
- '_date' => '',
- 'payby' => 'COMP',
- 'payinfo' => $self->cust_main->payinfo,
- 'paybatch' => '',
- } );
- $cust_pay->insert;
-}
-
-=item realtime_card
-
-Attempts to pay this invoice with a credit card payment via a
-Business::OnlinePayment realtime gateway. See
-http://search.cpan.org/search?mode=module&query=Business%3A%3AOnlinePayment
-for supported processors.
-
-=cut
-
-sub realtime_card {
- my $self = shift;
- $self->realtime_bop( 'CC', @_ );
-}
-
-=item realtime_ach
-
-Attempts to pay this invoice with an electronic check (ACH) payment via a
-Business::OnlinePayment realtime gateway. See
-http://search.cpan.org/search?mode=module&query=Business%3A%3AOnlinePayment
-for supported processors.
-
-=cut
-
-sub realtime_ach {
- my $self = shift;
- $self->realtime_bop( 'ECHECK', @_ );
-}
-
-=item realtime_lec
-
-Attempts to pay this invoice with phone bill (LEC) payment via a
-Business::OnlinePayment realtime gateway. See
-http://search.cpan.org/search?mode=module&query=Business%3A%3AOnlinePayment
-for supported processors.
-
-=cut
-
-sub realtime_lec {
- my $self = shift;
- $self->realtime_bop( 'LEC', @_ );
-}
-
-sub realtime_bop {
- my( $self, $method ) = (shift,shift);
- my $conf = $self->conf;
- my %opt = @_;
-
- my $cust_main = $self->cust_main;
- my $balance = $cust_main->balance;
- my $amount = ( $balance < $self->owed ) ? $balance : $self->owed;
- $amount = sprintf("%.2f", $amount);
- return "not run (balance $balance)" unless $amount > 0;
-
- my $description = 'Internet Services';
- if ( $conf->exists('business-onlinepayment-description') ) {
- my $dtempl = $conf->config('business-onlinepayment-description');
-
- my $agent_obj = $cust_main->agent
- or die "can't retreive agent for $cust_main (agentnum ".
- $cust_main->agentnum. ")";
- my $agent = $agent_obj->agent;
- my $pkgs = join(', ',
- map { $_->part_pkg->pkg }
- grep { $_->pkgnum } $self->cust_bill_pkg
- );
- $description = eval qq("$dtempl");
- }
-
- $cust_main->realtime_bop($method, $amount,
- 'description' => $description,
- 'invnum' => $self->invnum,
-#this didn't do what we want, it just calls apply_payments_and_credits
-# 'apply' => 1,
- 'apply_to_invoice' => 1,
- %opt,
- #what we want:
- #this changes application behavior: auto payments
- #triggered against a specific invoice are now applied
- #to that invoice instead of oldest open.
- #seem okay to me...
- );
-
-}
-
-=item batch_card OPTION => VALUE...
-
-Adds a payment for this invoice to the pending credit card batch (see
-L<FS::cust_pay_batch>), or, if the B<realtime> option is set to a true value,
-runs the payment using a realtime gateway.
-
-=cut
-
-sub batch_card {
- my ($self, %options) = @_;
- my $cust_main = $self->cust_main;
-
- $options{invnum} = $self->invnum;
-
- $cust_main->batch_card(%options);
-}
-
-sub _agent_template {
- my $self = shift;
- $self->cust_main->agent_template;
-}
-
-sub _agent_invoice_from {
- my $self = shift;
- $self->cust_main->agent_invoice_from;
-}
-
-=item print_text HASHREF | [ TIME [ , TEMPLATE [ , OPTION => VALUE ... ] ] ]
-
-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.
-
-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<notice_name>, if specified, overrides "Invoice" as the name of the sent document (templates from 10/2009 or newer required)
-
-=cut
-
-sub print_text {
- my $self = shift;
- my( $today, $template, %opt );
- if ( ref($_[0]) ) {
- %opt = %{ shift() };
- $today = delete($opt{'time'}) || '';
- $template = delete($opt{template}) || '';
- } else {
- ( $today, $template, %opt ) = @_;
- }
-
- my %params = ( 'format' => 'template' );
- $params{'time'} = $today if $today;
- $params{'template'} = $template if $template;
- $params{$_} = $opt{$_}
- foreach grep $opt{$_}, qw( unsquelch_cdr notice_name );
-
- $self->print_generic( %params );
-}
-
-=item print_latex HASHREF | [ TIME [ , TEMPLATE [ , OPTION => VALUE ... ] ] ]
-
-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
-an associated logo (with the .eps extension included).
-
-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.
-
-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<notice_name>, if specified, overrides "Invoice" as the name of the sent document (templates from 10/2009 or newer required)
-
-=cut
-
-sub print_latex {
- my $self = shift;
- my $conf = $self->conf;
- my( $today, $template, %opt );
- if ( ref($_[0]) ) {
- %opt = %{ shift() };
- $today = delete($opt{'time'}) || '';
- $template = delete($opt{template}) || '';
- } else {
- ( $today, $template, %opt ) = @_;
- }
-
- my %params = ( 'format' => 'latex' );
- $params{'time'} = $today if $today;
- $params{'template'} = $template if $template;
- $params{$_} = $opt{$_}
- foreach grep $opt{$_}, qw( unsquelch_cdr notice_name );
-
- $template ||= $self->_agent_template;
-
- my $dir = $FS::UID::conf_dir. "/cache.". $FS::UID::datasrc;
- my $lh = new File::Temp( TEMPLATE => 'invoice.'. $self->invnum. '.XXXXXXXX',
- DIR => $dir,
- SUFFIX => '.eps',
- UNLINK => 0,
- ) or die "can't open temp file: $!\n";
-
- my $agentnum = $self->cust_main->agentnum;
-
- if ( $template && $conf->exists("logo_${template}.eps", $agentnum) ) {
- print $lh $conf->config_binary("logo_${template}.eps", $agentnum)
- or die "can't write temp file: $!\n";
- } else {
- print $lh $conf->config_binary('logo.eps', $agentnum)
- or die "can't write temp file: $!\n";
- }
- close $lh;
- $params{'logo_file'} = $lh->filename;
-
- if($conf->exists('invoice-barcode')){
- my $png_file = $self->invoice_barcode($dir);
- my $eps_file = $png_file;
- $eps_file =~ s/\.png$/.eps/g;
- $png_file =~ /(barcode.*png)/;
- $png_file = $1;
- $eps_file =~ /(barcode.*eps)/;
- $eps_file = $1;
-
- my $curr_dir = cwd();
- chdir($dir);
- # after painfuly long experimentation, it was determined that sam2p won't
- # accept : and other chars in the path, no matter how hard I tried to
- # escape them, hence the chdir (and chdir back, just to be safe)
- system('sam2p', '-j:quiet', $png_file, 'EPS:', $eps_file ) == 0
- or die "sam2p failed: $!\n";
- unlink($png_file);
- chdir($curr_dir);
-
- $params{'barcode_file'} = $eps_file;
- }
-
- my @filled_in = $self->print_generic( %params );
-
- my $fh = new File::Temp( TEMPLATE => 'invoice.'. $self->invnum. '.XXXXXXXX',
- DIR => $dir,
- SUFFIX => '.tex',
- UNLINK => 0,
- ) or die "can't open temp file: $!\n";
- binmode($fh, ':utf8'); # language support
- print $fh join('', @filled_in );
- close $fh;
-
- $fh->filename =~ /^(.*).tex$/ or die "unparsable filename: ". $fh->filename;
- return ($1, $params{'logo_file'}, $params{'barcode_file'});
-
-}
-
-=item invoice_barcode DIR_OR_FALSE
-
-Generates an invoice barcode PNG. If DIR_OR_FALSE is a true value,
-it is taken as the temp directory where the PNG file will be generated and the
-PNG file name is returned. Otherwise, the PNG image itself is returned.
-
-=cut
-
-sub invoice_barcode {
- my ($self, $dir) = (shift,shift);
-
- my $gdbar = new GD::Barcode('Code39',$self->invnum);
- die "can't create barcode: " . $GD::Barcode::errStr unless $gdbar;
- my $gd = $gdbar->plot(Height => 30);
-
- if($dir) {
- my $bh = new File::Temp( TEMPLATE => 'barcode.'. $self->invnum. '.XXXXXXXX',
- DIR => $dir,
- SUFFIX => '.png',
- UNLINK => 0,
- ) or die "can't open temp file: $!\n";
- print $bh $gd->png or die "cannot write barcode to file: $!\n";
- my $png_file = $bh->filename;
- close $bh;
- return $png_file;
- }
- return $gd->png;
-}
-
-=item print_generic OPTION => VALUE ...
-
-Internal method - returns a filled-in template for this invoice as a scalar.
-
-See print_ps and print_pdf for methods that return PostScript and PDF output.
-
-Non optional options include
- format - latex, html, template
-
-Optional options include
-
-template - a value used as a suffix for a configuration template
-
-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.
-It is specified as a UNIX timestamp; see L<perlfunc/"time">. Also see
-L<Time::Local> and L<Date::Parse> for conversion functions.
-
-cid -
-
-unsquelch_cdr - overrides any per customer cdr squelching when true
-
-notice_name - overrides "Invoice" as the name of the sent document (templates from 10/2009 or newer required)
-
-locale - override customer's locale
-
-=cut
-
-#what's with all the sprintf('%10.2f')'s in here? will it cause any
-# (alignment in text invoice?) problems to change them all to '%.2f' ?
-# yes: fixed width/plain text printing will be borked
-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;
-
- my $format = $params{format};
- die "Unknown format: $format"
- unless $format =~ /^(latex|html|template)$/;
-
- my $cust_main = $self->cust_main;
- $cust_main->payname( $cust_main->first. ' '. $cust_main->getfield('last') )
- unless $cust_main->payname
- && $cust_main->payby !~ /^(CARD|DCRD|CHEK|DCHK)$/;
-
- my %delimiters = ( 'latex' => [ '[@--', '--@]' ],
- 'html' => [ '<%=', '%>' ],
- 'template' => [ '{', '}' ],
- );
-
- warn "$me print_generic creating template\n"
- if $DEBUG > 1;
-
- #create the template
- my $template = $params{template} ? $params{template} : $self->_agent_template;
- my $templatefile = "invoice_$format";
- $templatefile .= "_$template"
- if length($template) && $conf->exists($templatefile."_$template");
- my @invoice_template = map "$_\n", $conf->config($templatefile)
- or die "cannot load config data $templatefile";
-
- my $old_latex = '';
- if ( $format eq 'latex' && grep { /^%%Detail/ } @invoice_template ) {
- #change this to a die when the old code is removed
- warn "old-style invoice template $templatefile; ".
- "patch with conf/invoice_latex.diff or use new conf/invoice_latex*\n";
- $old_latex = 'true';
- @invoice_template = _translate_old_latex_format(@invoice_template);
- }
-
- warn "$me print_generic creating T:T object\n"
- if $DEBUG > 1;
-
- my $text_template = new Text::Template(
- TYPE => 'ARRAY',
- SOURCE => \@invoice_template,
- DELIMITERS => $delimiters{$format},
- );
-
- warn "$me print_generic compiling T:T object\n"
- if $DEBUG > 1;
-
- $text_template->compile()
- or die "Can't compile $templatefile: $Text::Template::ERROR\n";
-
-
- # additional substitution could possibly cause breakage in existing templates
- my %convert_maps = (
- 'latex' => {
- 'notes' => sub { map "$_", @_ },
- 'footer' => sub { map "$_", @_ },
- 'smallfooter' => sub { map "$_", @_ },
- 'returnaddress' => sub { map "$_", @_ },
- 'coupon' => sub { map "$_", @_ },
- 'summary' => sub { map "$_", @_ },
- },
- 'html' => {
- 'notes' =>
- sub {
- map {
- s/%%(.*)$/<!-- $1 -->/g;
- s/\\section\*\{\\textsc\{(.)(.*)\}\}/<p><b><font size="+1">$1<\/font>\U$2<\/b>/g;
- s/\\begin\{enumerate\}/<ol>/g;
- s/\\item / <li>/g;
- s/\\end\{enumerate\}/<\/ol>/g;
- s/\\textbf\{(.*)\}/<b>$1<\/b>/g;
- s/\\\\\*/<br>/g;
- s/\\dollar ?/\$/g;
- s/\\#/#/g;
- s/~/ /g;
- $_;
- } @_
- },
- 'footer' =>
- sub { map { s/~/ /g; s/\\\\\*?\s*$/<BR>/; $_; } @_ },
- 'smallfooter' =>
- sub { map { s/~/ /g; s/\\\\\*?\s*$/<BR>/; $_; } @_ },
- 'returnaddress' =>
- sub {
- map {
- s/~/ /g;
- s/\\\\\*?\s*$/<BR>/;
- s/\\hyphenation\{[\w\s\-]+}//;
- s/\\([&])/$1/g;
- $_;
- } @_
- },
- 'coupon' => sub { "" },
- 'summary' => sub { "" },
- },
- 'template' => {
- 'notes' =>
- sub {
- map {
- s/%%.*$//g;
- s/\\section\*\{\\textsc\{(.*)\}\}/\U$1/g;
- s/\\begin\{enumerate\}//g;
- s/\\item / * /g;
- s/\\end\{enumerate\}//g;
- s/\\textbf\{(.*)\}/$1/g;
- s/\\\\\*/ /;
- s/\\dollar ?/\$/g;
- $_;
- } @_
- },
- 'footer' =>
- sub { map { s/~/ /g; s/\\\\\*?\s*$/\n/; $_; } @_ },
- 'smallfooter' =>
- sub { map { s/~/ /g; s/\\\\\*?\s*$/\n/; $_; } @_ },
- 'returnaddress' =>
- sub {
- map {
- s/~/ /g;
- s/\\\\\*?\s*$/\n/; # dubious
- s/\\hyphenation\{[\w\s\-]+}//;
- $_;
- } @_
- },
- 'coupon' => sub { "" },
- 'summary' => sub { "" },
- },
- );
-
-
- # hashes for differing output formats
- my %nbsps = ( 'latex' => '~',
- 'html' => '', # '&nbps;' would be nice
- 'template' => '', # not used
- );
- my $nbsp = $nbsps{$format};
-
- my %escape_functions = ( 'latex' => \&_latex_escape,
- 'html' => \&_html_escape_nbsp,#\&encode_entities,
- 'template' => sub { shift },
- );
- my $escape_function = $escape_functions{$format};
- my $escape_function_nonbsp = ($format eq 'html')
- ? \&_html_escape : $escape_function;
-
- my %date_formats = ( 'latex' => $date_format_long,
- 'html' => $date_format_long,
- 'template' => '%s',
- );
- $date_formats{'html'} =~ s/ / /g;
-
- my $date_format = $date_formats{$format};
-
- my %embolden_functions = ( 'latex' => sub { return '\textbf{'. shift(). '}'
- },
- 'html' => sub { return '<b>'. shift(). '</b>'
- },
- 'template' => sub { shift },
- );
- my $embolden_function = $embolden_functions{$format};
-
- my %newline_tokens = ( 'latex' => '\\\\',
- 'html' => '<br>',
- 'template' => "\n",
- );
- my $newline_token = $newline_tokens{$format};
-
- warn "$me generating template variables\n"
- if $DEBUG > 1;
-
- # generate template variables
- my $returnaddress;
- if (
- defined( $conf->config_orbase( "invoice_${format}returnaddress",
- $template
- )
- )
- && length( $conf->config_orbase( "invoice_${format}returnaddress",
- $template
- )
- )
- ) {
-
- $returnaddress = join("\n",
- $conf->config_orbase("invoice_${format}returnaddress", $template)
- );
-
- } elsif ( grep /\S/,
- $conf->config_orbase('invoice_latexreturnaddress', $template) ) {
-
- my $convert_map = $convert_maps{$format}{'returnaddress'};
- $returnaddress =
- join( "\n",
- &$convert_map( $conf->config_orbase( "invoice_latexreturnaddress",
- $template
- )
- )
- );
- } elsif ( grep /\S/, $conf->config('company_address', $self->cust_main->agentnum) ) {
-
- my $convert_map = $convert_maps{$format}{'returnaddress'};
- $returnaddress = join( "\n", &$convert_map(
- map { s/( {2,})/'~' x length($1)/eg;
- s/$/\\\\\*/;
- $_
- }
- ( $conf->config('company_name', $self->cust_main->agentnum),
- $conf->config('company_address', $self->cust_main->agentnum),
- )
- )
- );
-
- } else {
-
- my $warning = "Couldn't find a return address; ".
- "do you need to set the company_address configuration value?";
- warn "$warning\n";
- $returnaddress = $nbsp;
- #$returnaddress = $warning;
-
- }
-
- warn "$me generating invoice data\n"
- if $DEBUG > 1;
-
- my $agentnum = $self->cust_main->agentnum;
-
- my %invoice_data = (
-
- #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),
-
- #invoice info
- 'invnum' => $self->invnum,
- 'date' => time2str($date_format, $self->_date),
- 'today' => time2str($date_format_long, $today),
- 'terms' => $self->terms,
- 'template' => $template, #params{'template'},
- 'notice_name' => ($params{'notice_name'} || 'Invoice'),#escape_function?
- 'current_charges' => sprintf("%.2f", $self->charged),
- 'duedate' => $self->due_date2str($rdate_format), #date_format?
-
- #customer info
- 'custnum' => $cust_main->display_custnum,
- 'agent_custid' => &$escape_function($cust_main->agent_custid),
- ( map { $_ => &$escape_function($cust_main->$_()) } qw(
- payname company address1 address2 city state zip fax
- )),
-
- #global config
- 'ship_enable' => $conf->exists('invoice-ship_address'),
- 'unitprices' => $conf->exists('invoice-unitprice'),
- 'smallernotes' => $conf->exists('invoice-smallernotes'),
- 'smallerfooter' => $conf->exists('invoice-smallerfooter'),
- 'balance_due_below_line' => $conf->exists('balance_due_below_line'),
-
- #layout info -- would be fancy to calc some of this and bury the template
- # here in the code
- 'topmargin' => scalar($conf->config('invoice_latextopmargin', $agentnum)),
- 'headsep' => scalar($conf->config('invoice_latexheadsep', $agentnum)),
- 'textheight' => scalar($conf->config('invoice_latextextheight', $agentnum)),
- 'extracouponspace' => scalar($conf->config('invoice_latexextracouponspace', $agentnum)),
- 'couponfootsep' => scalar($conf->config('invoice_latexcouponfootsep', $agentnum)),
- 'verticalreturnaddress' => $conf->exists('invoice_latexverticalreturnaddress', $agentnum),
- 'addresssep' => scalar($conf->config('invoice_latexaddresssep', $agentnum)),
- 'amountenclosedsep' => scalar($conf->config('invoice_latexcouponamountenclosedsep', $agentnum)),
- 'coupontoaddresssep' => scalar($conf->config('invoice_latexcoupontoaddresssep', $agentnum)),
- 'addcompanytoaddress' => $conf->exists('invoice_latexcouponaddcompanytoaddress', $agentnum),
-
- # better hang on to conf_dir for a while (for old templates)
- 'conf_dir' => "$FS::UID::conf_dir/conf.$FS::UID::datasrc",
-
- #these are only used when doing paged plaintext
- 'page' => 1,
- 'total_pages' => 1,
-
- );
-
- #localization
- my $lh = FS::L10N->get_handle( $params{'locale'} || $cust_main->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
- my $dh = eval { Date::Language->new($info{'name'}) } ||
- Date::Language->new(); # fall back to English
- # prototype here to silence warnings
- $invoice_data{'time2str'} = sub ($;$$) { $dh->time2str(@_) };
- # eventually use this date handle everywhere in here, too
-
- my $min_sdate = 999999999999;
- my $max_edate = 0;
- foreach my $cust_bill_pkg ( $self->cust_bill_pkg ) {
- next unless $cust_bill_pkg->pkgnum > 0;
- $min_sdate = $cust_bill_pkg->sdate
- if length($cust_bill_pkg->sdate) && $cust_bill_pkg->sdate < $min_sdate;
- $max_edate = $cust_bill_pkg->edate
- if length($cust_bill_pkg->edate) && $cust_bill_pkg->edate > $max_edate;
- }
-
- $invoice_data{'bill_period'} = '';
- $invoice_data{'bill_period'} = time2str('%e %h', $min_sdate)
- . " to " . time2str('%e %h', $max_edate)
- if ($max_edate != 0 && $min_sdate != 999999999999);
-
- $invoice_data{finance_section} = '';
- if ( $conf->config('finance_pkgclass') ) {
- my $pkg_class =
- qsearchs('pkg_class', { classnum => $conf->config('finance_pkgclass') });
- $invoice_data{finance_section} = $pkg_class->categoryname;
- }
- $invoice_data{finance_amount} = '0.00';
- $invoice_data{finance_section} ||= 'Finance Charges'; #avoid config confusion
-
- my $countrydefault = $conf->config('countrydefault') || 'US';
- my $prefix = $cust_main->has_ship_address ? 'ship_' : '';
- foreach ( qw( contact company address1 address2 city state zip country fax) ){
- my $method = $prefix.$_;
- $invoice_data{"ship_$_"} = _latex_escape($cust_main->$method);
- }
- $invoice_data{'ship_country'} = ''
- if ( $invoice_data{'ship_country'} eq $countrydefault );
-
- $invoice_data{'cid'} = $params{'cid'}
- if $params{'cid'};
-
- if ( $cust_main->country eq $countrydefault ) {
- $invoice_data{'country'} = '';
- } else {
- $invoice_data{'country'} = &$escape_function(code2country($cust_main->country));
- }
-
- my @address = ();
- $invoice_data{'address'} = \@address;
- push @address,
- $cust_main->payname.
- ( ( $cust_main->payby eq 'BILL' ) && $cust_main->payinfo
- ? " (P.O. #". $cust_main->payinfo. ")"
- : ''
- )
- ;
- push @address, $cust_main->company
- if $cust_main->company;
- push @address, $cust_main->address1;
- push @address, $cust_main->address2
- if $cust_main->address2;
- push @address,
- $cust_main->city. ", ". $cust_main->state. " ". $cust_main->zip;
- push @address, $invoice_data{'country'}
- if $invoice_data{'country'};
- push @address, ''
- while (scalar(@address) < 5);
-
- $invoice_data{'logo_file'} = $params{'logo_file'}
- if $params{'logo_file'};
- $invoice_data{'barcode_file'} = $params{'barcode_file'}
- if $params{'barcode_file'};
- $invoice_data{'barcode_img'} = $params{'barcode_img'}
- if $params{'barcode_img'};
- $invoice_data{'barcode_cid'} = $params{'barcode_cid'}
- if $params{'barcode_cid'};
-
- my( $pr_total, @pr_cust_bill ) = $self->previous; #previous balance
-# my( $cr_total, @cr_cust_credit ) = $self->cust_credit; #credits
- #my $balance_due = $self->owed + $pr_total - $cr_total;
- my $balance_due = $self->owed + $pr_total;
-
- # the customer's current balance as shown on the invoice before this one
- $invoice_data{'true_previous_balance'} = sprintf("%.2f", ($self->previous_balance || 0) );
-
- # the change in balance from that invoice to this one
- $invoice_data{'balance_adjustments'} = sprintf("%.2f", ($self->previous_balance || 0) - ($self->billing_balance || 0) );
-
- # the sum of amount owed on all previous invoices
- $invoice_data{'previous_balance'} = sprintf("%.2f", $pr_total);
-
- # the sum of amount owed on all invoices
- $invoice_data{'balance'} = sprintf("%.2f", $balance_due);
-
- # info from customer's last invoice before this one, for some
- # summary formats
- $invoice_data{'last_bill'} = {};
- my $last_bill = $pr_cust_bill[-1];
- if ( $last_bill ) {
- $invoice_data{'last_bill'} = {
- '_date' => $last_bill->_date, #unformatted
- # all we need for now
- };
- }
-
- my $summarypage = '';
- if ( $conf->exists('invoice_usesummary', $agentnum) ) {
- $summarypage = 1;
- }
- $invoice_data{'summarypage'} = $summarypage;
-
- warn "$me substituting variables in notes, footer, smallfooter\n"
- if $DEBUG > 1;
-
- my @include = (qw( notes footer smallfooter ));
- push @include, 'coupon' unless $params{'no_coupon'};
- foreach my $include (@include) {
-
- my $inc_file = $conf->key_orbase("invoice_${format}$include", $template);
- my @inc_src;
-
- if ( $conf->exists($inc_file, $agentnum)
- && length( $conf->config($inc_file, $agentnum) ) ) {
-
- @inc_src = $conf->config($inc_file, $agentnum);
-
- } else {
-
- $inc_file = $conf->key_orbase("invoice_latex$include", $template);
-
- my $convert_map = $convert_maps{$format}{$include};
-
- @inc_src = map { s/\[\@--/$delimiters{$format}[0]/g;
- s/--\@\]/$delimiters{$format}[1]/g;
- $_;
- }
- &$convert_map( $conf->config($inc_file, $agentnum) );