use vars qw( @ISA $DEBUG $me $conf $money_char );
use vars qw( $invoice_lines @buf ); #yuck
use Fcntl qw(:flock); #for spool_csv
+use List::Util qw(min max);
use IPC::Run3;
use Date::Format;
use Text::Template 1.20;
qsearch( 'cust_bill_pkg', { 'invnum' => $self->invnum } );
}
+=item cust_pkg
+
+Returns the packages (see L<FS::cust_pkg>) corresponding to the line items for
+this invoice.
+
+=cut
+
+sub cust_pkg {
+ my $self = shift;
+ my @cust_pkg = map { $_->cust_pkg } $self->cust_bill_pkg;
+ my %saw = ();
+ grep { ! $saw{$_->pkgnum}++ } @cust_pkg;
+}
+
=item open_cust_bill_pkg
Returns the open line items for this invoice.
if ( $cust_main->total_owed_date($self->_date) < $amount ) {
return ();
} else {
- $cust_main->suspend;
+ $cust_main->suspend(@_);
}
}
$balance;
}
+=item apply_payments_and_credits
+
+=cut
+
+sub apply_payments_and_credits {
+ my $self = shift;
+
+ my @payments = grep { $_->unapplied > 0 } $self->cust_main->cust_pay;
+ my @credits = grep { $_->credited > 0 } $self->cust_main->cust_credit;
+
+ while ( $self->owed > 0 and ( @payments || @credits ) ) {
+
+ my $app = '';
+ if ( @payments && @credits ) {
+
+ #decide which goes first by weight of top (unapplied) line item
+
+ my @open_lineitems = $self->open_cust_bill_pkg;
+
+ my $max_pay_weight =
+ max( map { $_->cust_pkg->part_pkg->pay_weight || 0 }
+ @open_lineitems
+ );
+ my $max_credit_weight =
+ max( map { $_->cust_pkg->part_pkg->credit_weight || 0 }
+ @open_lineitems
+ );
+
+ #if both are the same... payments first? it has to be something
+ if ( $max_pay_weight >= $max_credit_weight ) {
+ $app = 'pay';
+ } else {
+ $app = 'credit';
+ }
+
+ } elsif ( @payments ) {
+ $app = 'pay';
+ } elsif ( @credits ) {
+ $app = 'credit';
+ } else {
+ die "guru meditation #12 and 35";
+ }
+
+ if ( $app eq 'pay' ) {
+
+ my $payment = shift @payments;
+
+ $app = new FS::cust_bill_pay {
+ 'paynum' => $payment->paynum,
+ 'amount' => sprintf('%.2f', min( $payment->unapplied, $self->owed ) ),
+ };
+
+ } elsif ( $app eq 'credit' ) {
+
+ my $credit = shift @credits;
+
+ $app = new FS::cust_credit_bill {
+ 'crednum' => $credit->crednum,
+ 'amount' => sprintf('%.2f', min( $credit->credited, $self->owed ) ),
+ };
+
+ } else {
+ die "guru meditation #12 and 35";
+ }
+
+ $app->invnum( $self->invnum );
+
+ my $error = $app->insert;
+ die $error if $error;
+
+ }
+
+}
=item generate_email PARAMHASH
'Disposition' => 'inline',
);
- $args{'from'} =~ /\@([\w\.\-]+)/ or $1 = 'example.com';
- my $content_id = join('.', rand()*(2**32), $$, time). "\@$1";
+ $args{'from'} =~ /\@([\w\.\-]+)/;
+ my $from = $1 || 'example.com';
+ my $content_id = join('.', rand()*(2**32), $$, time). "\@$from";
my $path = "$FS::UID::conf_dir/conf.$FS::UID::datasrc";
my $file;
- if ( defined($args{'_template'}) && length($args{'_template'})
- && -e "$path/logo_". $args{'_template'}. ".png"
+ if ( defined($args{'template'}) && length($args{'template'})
+ && -e "$path/logo_". $args{'template'}. ".png"
)
{
- $file = "$path/logo_". $args{'_template'}. ".png";
+ $file = "$path/logo_". $args{'template'}. ".png";
} else {
$file = "$path/logo.png";
}
=cut
+sub queueable_send {
+ my %opt = @_;
+
+ my $self = qsearchs('cust_bill', { 'invnum' => $opt{invnum} } )
+ or die "invalid invoice number: " . $opt{invnum};
+
+ my $error = $self->send($opt{template}, $opt{agentnum}, $opt{invoice_from});
+
+ die $error if $error;
+}
+
sub send {
my $self = shift;
my $template = scalar(@_) ? shift : '';
#setup template variables
package FS::cust_bill::_template; #!
- use vars qw( $invnum $date $page $total_pages @address $overdue @buf $agent );
+ use vars qw( $custnum $invnum $date $agent @address $overdue
+ $page $total_pages @buf );
+ $custnum = $self->custnum;
$invnum = $self->invnum;
$date = $self->_date;
- $page = 1;
$agent = $self->cust_main->agent->agent;
+ $page = 1;
if ( $FS::cust_bill::invoice_lines ) {
$total_pages =
}
my %invoice_data = (
+ 'custnum' => $self->custnum,
'invnum' => $self->invnum,
'date' => time2str('%b %o, %Y', $self->_date),
'today' => time2str('%b %o, %Y', $today),
or die 'While compiling ' . $templatefile . ': ' . $Text::Template::ERROR;
my %invoice_data = (
+ 'custnum' => $self->custnum,
'invnum' => $self->invnum,
'date' => time2str('%b %o, %Y', $self->_date),
'today' => time2str('%b %o, %Y', $today),
s/\\item / <li>/;
s/\\end\{enumerate\}/<\/ol>/;
s/\\textbf\{(.*)\}/<b>$1<\/b>/;
+ s/\\\\\*/ /;
$_;
}
$conf->config_orbase('invoice_latexnotes', $template)