use Date::Format;
use Text::Template;
use File::Temp 0.14;
+use String::ShellQuote;
use FS::UID qw( datasrc );
use FS::Record qw( qsearch qsearchs );
use FS::Misc qw( send_email );
$balance;
}
-=item send [ TEMPLATENAME [ , AGENTNUM ] ]
+=item send [ TEMPLATENAME [ , AGENTNUM [ , INVOICE_FROM ] ] ]
Sends this invoice to the destinations configured for this customer: send
emails or print. See L<FS::cust_main_invoice>.
AGENTNUM, if specified, means that this invoice will only be sent for customers
of the specified agent.
+INVOICE_FROM, if specified, overrides the default email invoice From: address.
+
=cut
sub send {
my $self = shift;
my $template = scalar(@_) ? shift : '';
- return '' if scalar(@_) && $_[0] && $self->cust_main->agentnum ne shift;
+ return 'N/A' if scalar(@_) && $_[0] && $self->cust_main->agentnum != shift;
+ my $invoice_from =
+ scalar(@_)
+ ? shift
+ : ( $self->_agent_invoice_from || $conf->config('invoice_from') );
my @print_text = $self->print_text('', $template);
my @invoicing_list = $self->cust_main->invoicing_list;
if ( grep { $_ ne 'POST' } @invoicing_list or !@invoicing_list ) { #email
#better to notify this person than silence
- @invoicing_list = ($conf->config('invoice_from')) unless @invoicing_list;
+ @invoicing_list = ($invoice_from) unless @invoicing_list;
my $error = send_email(
- 'from' => $conf->config('invoice_from'),
+ 'from' => $invoice_from,
'to' => [ grep { $_ ne 'POST' } @invoicing_list ],
'subject' => 'Invoice',
'body' => \@print_text,
);
die "can't email invoice: $error\n" if $error;
+ #die "$error\n" if $error;
}
- if ( $conf->config('invoice_latex') ) {
- @print_text = $self->print_ps('', $template);
- }
-
if ( grep { $_ eq 'POST' } @invoicing_list ) { #postal
+ @print_text = $self->print_ps('', $template)
+ if $conf->config('invoice_latex');
my $lpr = $conf->config('lpr');
open(LPR, "|$lpr")
or die "Can't open pipe to $lpr: $!\n";
}
+=item send_if_newest [ TEMPLATENAME [ , AGENTNUM [ , INVOICE_FROM ] ] ]
+
+Like B<send>, but only sends the invoice if it is the newest open invoice for
+this customer.
+
+=cut
+
+sub send_if_newest {
+ my $self = shift;
+
+ return ''
+ if scalar(
+ grep { $_->owed > 0 }
+ qsearch('cust_bill', {
+ 'custnum' => $self->custnum,
+ #'_date' => { op=>'>', value=>$self->_date },
+ 'invnum' => { op=>'>', value=>$self->invnum },
+ } )
+ );
+
+ $self->send(@_);
+}
+
=item send_csv OPTIONS
Sends invoice as a CSV data-file to a remote host with the specified protocol.
sub _agent_template {
my $self = shift;
+ $self->_agent_plandata('agent_templatename');
+}
- my $cust_bill_event = qsearchs( 'part_bill_event',
+sub _agent_invoice_from {
+ my $self = shift;
+ $self->_agent_plandata('agent_invoice_from');
+}
+
+sub _agent_plandata {
+ my( $self, $option ) = @_;
+
+ my $part_bill_event = qsearchs( 'part_bill_event',
{
'payby' => $self->cust_main->payby,
'plan' => 'send_agent',
- 'eventcode' => { 'op' => 'LIKE',
- 'value' => '_%, '. $self->cust_main->agentnum. ');' },
+ 'plandata' => { 'op' => '~',
+ 'value' => "(^|\n)agentnum ".
+ $self->cust_main->agentnum.
+ "(\n|\$)",
+ },
},
'',
'ORDER BY seconds LIMIT 1'
);
- return '' unless $cust_bill_event;
+ return '' unless $part_bill_event;
- if ( $cust_bill_event->eventcode =~ /\(\s*'(.*)'\s*,\s*(\d+)\s*\)\;$/ ) {
+ if ( $part_bill_event->plandata =~ /^$option (.*)$/m ) {
return $1;
} else {
- warn "can't parse eventcode for agent-specific invoice template";
+ warn "can't parse part_bill_event eventpart#". $part_bill_event->eventpart.
+ " plandata for $option";
return '';
}
=cut
+#still some false laziness w/print_text
sub print_text {
my( $self, $today, $template ) = @_;
$today ||= time;
+
# my $invnum = $self->invnum;
- my $cust_main = qsearchs('cust_main', { 'custnum', $self->custnum } );
+ my $cust_main = $self->cust_main;
$cust_main->payname( $cust_main->first. ' '. $cust_main->getfield('last') )
- unless $cust_main->payname && $cust_main->payby ne 'CHEK';
+ unless $cust_main->payname && $cust_main->payby !~ /^(CHEK|DCHK)$/;
my( $pr_total, @pr_cust_bill ) = $self->previous; #previous balance
# my( $cr_total, @cr_cust_credit ) = $self->cust_credit; #credits
push @buf, [ $description,
$money_char. sprintf("%10.2f", $cust_bill_pkg->setup) ];
push @buf,
- map { [ " ". $_->[0]. ": ". $_->[1], '' ] } $cust_pkg->labels;
+ map { [ " ". $_->[0]. ": ". $_->[1], '' ] }
+ $cust_pkg->h_labels($self->_date);
}
if ( $cust_bill_pkg->recur != 0 ) {
$money_char. sprintf("%10.2f", $cust_bill_pkg->recur)
];
push @buf,
- map { [ " ". $_->[0]. ": ". $_->[1], '' ] } $cust_pkg->labels;
+ map { [ " ". $_->[0]. ": ". $_->[1], '' ] }
+ $cust_pkg->h_labels($cust_bill_pkg->edate, $cust_bill_pkg->sdate);
}
push @buf, map { [ " $_", '' ] } $cust_bill_pkg->details;
# my $invnum = $self->invnum;
my $cust_main = $self->cust_main;
$cust_main->payname( $cust_main->first. ' '. $cust_main->getfield('last') )
- unless $cust_main->payname && $cust_main->payby ne 'CHEK';
+ unless $cust_main->payname && $cust_main->payby !~ /^(CHEK|DCHK)$/;
my( $pr_total, @pr_cust_bill ) = $self->previous; #previous balance
# my( $cr_total, @cr_cust_credit ) = $self->cust_credit; #credits
my $dir = $FS::UID::conf_dir. "cache.". $FS::UID::datasrc;
chdir($dir);
- system("pslatex $file.tex >/dev/null 2>&1") == 0
+ my $sfile = shell_quote $file;
+
+ system("pslatex $sfile.tex >/dev/null 2>&1") == 0
or die "pslatex $file.tex failed: $!";
- system("pslatex $file.tex >/dev/null 2>&1") == 0
+ system("pslatex $sfile.tex >/dev/null 2>&1") == 0
or die "pslatex $file.tex failed: $!";
system('dvips', '-q', '-t', 'letter', "$file.dvi", '-o', "$file.ps" ) == 0
#system('pdflatex', "$file.tex");
#! LaTeX Error: Unknown graphics extension: .eps.
- system("pslatex $file.tex >/dev/null 2>&1") == 0
+ my $sfile = shell_quote $file;
+
+ system("pslatex $sfile.tex >/dev/null 2>&1") == 0
or die "pslatex $file.tex failed: $!";
- system("pslatex $file.tex >/dev/null 2>&1") == 0
+ system("pslatex $sfile.tex >/dev/null 2>&1") == 0
or die "pslatex $file.tex failed: $!";
#system('dvipdf', "$file.dvi", "$file.pdf" );
system(
- "dvips -q -t letter -f $file.dvi ".
- "| gs -q -dNOPAUSE -dBATCH -sDEVICE=pdfwrite -sOutputFile=$file.pdf ".
+ "dvips -q -t letter -f $sfile.dvi ".
+ "| gs -q -dNOPAUSE -dBATCH -sDEVICE=pdfwrite -sOutputFile=$sfile.pdf ".
" -c save pop -"
) == 0
or die "dvips | gs failed: $!";
sub _latex_escape {
my $value = shift;
- $value =~ s/([#\$%&~_\^{}])( )?/"\\$1". ( length($2) ? "\\$2" : '' )/ge;
+ $value =~ s/([#\$%&~_\^{}])( )?/"\\$1". ( ( defined($2) && length($2) ) ? "\\$2" : '' )/ge;
$value;
}
my $part_pkg = qsearchs('part_pkg', { pkgpart=>$cust_pkg->pkgpart } );
my $pkg = $part_pkg->pkg;
- my %labels;
- #tie %labels, 'Tie::IxHash';
- push @{ $labels{$_->[0]} }, $_->[1] foreach $cust_pkg->labels;
- my @ext_description;
- foreach my $label ( keys %labels ) {
- my @values = @{ $labels{$label} };
- my $num = scalar(@values);
- if ( $num > 5 ) {
- push @ext_description, "$label ($num)";
- } else {
- push @ext_description, map { "$label: $_" } @values;
- }
- }
-
if ( $cust_bill_pkg->setup != 0 ) {
my $description = $pkg;
$description .= ' Setup' if $cust_bill_pkg->recur != 0;
- my @d = @ext_description;
+ my @d = $cust_pkg->h_labels_short($self->_date);
push @d, $cust_bill_pkg->details if $cust_bill_pkg->recur == 0;
push @b, {
- 'description' => $description,
- #'pkgpart' => $part_pkg->pkgpart,
- 'pkgnum' => $cust_pkg->pkgnum,
- 'amount' => sprintf("%10.2f", $cust_bill_pkg->setup),
- 'ext_description' => \@d,
+ description => $description,
+ #pkgpart => $part_pkg->pkgpart,
+ pkgnum => $cust_pkg->pkgnum,
+ amount => sprintf("%10.2f", $cust_bill_pkg->setup),
+ ext_description => \@d,
};
}
if ( $cust_bill_pkg->recur != 0 ) {
push @b, {
- 'description' => "$pkg (" .
+ description => "$pkg (" .
time2str('%x', $cust_bill_pkg->sdate). ' - '.
time2str('%x', $cust_bill_pkg->edate). ')',
- #'pkgpart' => $part_pkg->pkgpart,
- 'pkgnum' => $cust_pkg->pkgnum,
- 'amount' => sprintf("%10.2f", $cust_bill_pkg->recur),
- 'ext_description' => [ @ext_description,
- $cust_bill_pkg->details,
- ],
+ #pkgpart => $part_pkg->pkgpart,
+ pkgnum => $cust_pkg->pkgnum,
+ amount => sprintf("%10.2f", $cust_bill_pkg->recur),
+ ext_description => [ $cust_pkg->h_labels_short($cust_bill_pkg->edate,
+ $cust_bill_pkg->sdate),
+ $cust_bill_pkg->details,
+ ],
};
}
#'description' => 'Credit ref\#'. $_->crednum.
# " (". time2str("%x",$_->cust_credit->_date) .")".
# $reason,
- 'description' => 'Credit applied'.
+ 'description' => 'Credit applied '.
time2str("%x",$_->cust_credit->_date). $reason,
'amount' => sprintf("%10.2f",$_->amount),
};