This commit was manufactured by cvs2svn to create branch 'BESTPRACTICAL'.
[freeside.git] / FS / FS / cust_bill.pm
diff --git a/FS/FS/cust_bill.pm b/FS/FS/cust_bill.pm
deleted file mode 100644 (file)
index 5a9fdd0..0000000
+++ /dev/null
@@ -1,976 +0,0 @@
-package FS::cust_bill;
-
-use strict;
-use vars qw( @ISA $conf $money_char );
-use vars qw( $lpr $invoice_from $smtpmachine );
-use vars qw( $processor );
-use vars qw( $xaction $E_NoErr );
-use vars qw( $bop_processor $bop_login $bop_password $bop_action @bop_options );
-use vars qw( $invoice_lines @buf ); #yuck
-use Date::Format;
-use Mail::Internet 1.44;
-use Mail::Header;
-use Text::Template;
-use FS::Record qw( qsearch qsearchs );
-use FS::cust_main;
-use FS::cust_bill_pkg;
-use FS::cust_credit;
-use FS::cust_pay;
-use FS::cust_pkg;
-use FS::cust_credit_bill;
-use FS::cust_pay_batch;
-use FS::cust_bill_event;
-
-@ISA = qw( FS::Record );
-
-#ask FS::UID to run this stuff for us later
-$FS::UID::callback{'FS::cust_bill'} = sub { 
-
-  $conf = new FS::Conf;
-
-  $money_char = $conf->config('money_char') || '$';  
-
-  $lpr = $conf->config('lpr');
-  $invoice_from = $conf->config('invoice_from');
-  $smtpmachine = $conf->config('smtpmachine');
-
-  if ( $conf->exists('cybercash3.2') ) {
-    require CCMckLib3_2;
-      #qw($MCKversion %Config InitConfig CCError CCDebug CCDebug2);
-    require CCMckDirectLib3_2;
-      #qw(SendCC2_1Server);
-    require CCMckErrno3_2;
-      #qw(MCKGetErrorMessage $E_NoErr);
-    import CCMckErrno3_2 qw($E_NoErr);
-
-    my $merchant_conf;
-    ($merchant_conf,$xaction)= $conf->config('cybercash3.2');
-    my $status = &CCMckLib3_2::InitConfig($merchant_conf);
-    if ( $status != $E_NoErr ) {
-      warn "CCMckLib3_2::InitConfig error:\n";
-      foreach my $key (keys %CCMckLib3_2::Config) {
-        warn "  $key => $CCMckLib3_2::Config{$key}\n"
-      }
-      my($errmsg) = &CCMckErrno3_2::MCKGetErrorMessage($status);
-      die "CCMckLib3_2::InitConfig fatal error: $errmsg\n";
-    }
-    $processor='cybercash3.2';
-  } elsif ( $conf->exists('business-onlinepayment') ) {
-    ( $bop_processor,
-      $bop_login,
-      $bop_password,
-      $bop_action,
-      @bop_options
-    ) = $conf->config('business-onlinepayment');
-    $bop_action ||= 'normal authorization';
-    eval "use Business::OnlinePayment";  
-    $processor="Business::OnlinePayment::$bop_processor";
-  }
-
-};
-
-=head1 NAME
-
-FS::cust_bill - Object methods for cust_bill records
-
-=head1 SYNOPSIS
-
-  use FS::cust_bill;
-
-  $record = new FS::cust_bill \%hash;
-  $record = new FS::cust_bill { 'column' => 'value' };
-
-  $error = $record->insert;
-
-  $error = $new_record->replace($old_record);
-
-  $error = $record->delete;
-
-  $error = $record->check;
-
-  ( $total_previous_balance, @previous_cust_bill ) = $record->previous;
-
-  @cust_bill_pkg_objects = $cust_bill->cust_bill_pkg;
-
-  ( $total_previous_credits, @previous_cust_credit ) = $record->cust_credit;
-
-  @cust_pay_objects = $cust_bill->cust_pay;
-
-  $tax_amount = $record->tax;
-
-  @lines = $cust_bill->print_text;
-  @lines = $cust_bill->print_text $time;
-
-=head1 DESCRIPTION
-
-An FS::cust_bill object represents an invoice; a declaration that a customer
-owes you money.  The specific charges are itemized as B<cust_bill_pkg> records
-(see L<FS::cust_bill_pkg>).  FS::cust_bill inherits from FS::Record.  The
-following fields are currently supported:
-
-=over 4
-
-=item invnum - primary key (assigned automatically for new invoices)
-
-=item custnum - customer (see L<FS::cust_main>)
-
-=item _date - specified as a UNIX timestamp; see L<perlfunc/"time">.  Also see
-L<Time::Local> and L<Date::Parse> for conversion functions.
-
-=item charged - amount of this invoice
-
-=item printed - deprecated
-
-=item closed - books closed flag, empty or `Y'
-
-=back
-
-=head1 METHODS
-
-=over 4
-
-=item new HASHREF
-
-Creates a new invoice.  To add the invoice to the database, see L<"insert">.
-Invoices are normally created by calling the bill method of a customer object
-(see L<FS::cust_main>).
-
-=cut
-
-sub table { 'cust_bill'; }
-
-=item insert
-
-Adds this invoice to the database ("Posts" the invoice).  If there is an error,
-returns the error, otherwise returns false.
-
-=item delete
-
-Currently unimplemented.  I don't remove invoices because there would then be
-no record you ever posted this invoice (which is bad, no?)
-
-=cut
-
-sub delete {
-  my $self = shift;
-  return "Can't delete closed invoice" if $self->closed =~ /^Y/i;
-  $self->SUPER::delete(@_);
-}
-
-=item replace OLD_RECORD
-
-Replaces the OLD_RECORD with this one in the database.  If there is an error,
-returns the error, otherwise returns false.
-
-Only printed may be changed.  printed is normally updated by calling the
-collect method of a customer object (see L<FS::cust_main>).
-
-=cut
-
-sub replace {
-  my( $new, $old ) = ( shift, shift );
-  return "Can't change custnum!" unless $old->custnum == $new->custnum;
-  #return "Can't change _date!" unless $old->_date eq $new->_date;
-  return "Can't change _date!" unless $old->_date == $new->_date;
-  return "Can't change charged!" unless $old->charged == $new->charged;
-
-  $new->SUPER::replace($old);
-}
-
-=item check
-
-Checks all fields to make sure this is a valid invoice.  If there is an error,
-returns the error, otherwise returns false.  Called by the insert and replace
-methods.
-
-=cut
-
-sub check {
-  my $self = shift;
-
-  my $error =
-    $self->ut_numbern('invnum')
-    || $self->ut_number('custnum')
-    || $self->ut_numbern('_date')
-    || $self->ut_money('charged')
-    || $self->ut_numbern('printed')
-    || $self->ut_enum('closed', [ '', 'Y' ])
-  ;
-  return $error if $error;
-
-  return "Unknown customer"
-    unless qsearchs( 'cust_main', { 'custnum' => $self->custnum } );
-
-  $self->_date(time) unless $self->_date;
-
-  $self->printed(0) if $self->printed eq '';
-
-  ''; #no error
-}
-
-=item previous
-
-Returns a list consisting of the total previous balance for this customer, 
-followed by the previous outstanding invoices (as FS::cust_bill objects also).
-
-=cut
-
-sub previous {
-  my $self = shift;
-  my $total = 0;
-  my @cust_bill = sort { $a->_date <=> $b->_date }
-    grep { $_->owed != 0 && $_->_date < $self->_date }
-      qsearch( 'cust_bill', { 'custnum' => $self->custnum } ) 
-  ;
-  foreach ( @cust_bill ) { $total += $_->owed; }
-  $total, @cust_bill;
-}
-
-=item cust_bill_pkg
-
-Returns the line items (see L<FS::cust_bill_pkg>) for this invoice.
-
-=cut
-
-sub cust_bill_pkg {
-  my $self = shift;
-  qsearch( 'cust_bill_pkg', { 'invnum' => $self->invnum } );
-}
-
-=item cust_bill_event
-
-Returns the completed invoice events (see L<FS::cust_bill_event>) for this
-invoice.
-
-=cut
-
-sub cust_bill_event {
-  my $self = shift;
-  qsearch( 'cust_bill_event', { 'invnum' => $self->invnum } );
-}
-
-
-=item cust_main
-
-Returns the customer (see L<FS::cust_main>) for this invoice.
-
-=cut
-
-sub cust_main {
-  my $self = shift;
-  qsearchs( 'cust_main', { 'custnum' => $self->custnum } );
-}
-
-=item cust_credit
-
-Depreciated.  See the cust_credited method.
-
- #Returns a list consisting of the total previous credited (see
- #L<FS::cust_credit>) and unapplied for this customer, followed by the previous
- #outstanding credits (FS::cust_credit objects).
-
-=cut
-
-sub cust_credit {
-  use Carp;
-  croak "FS::cust_bill->cust_credit depreciated; see ".
-        "FS::cust_bill->cust_credit_bill";
-  #my $self = shift;
-  #my $total = 0;
-  #my @cust_credit = sort { $a->_date <=> $b->_date }
-  #  grep { $_->credited != 0 && $_->_date < $self->_date }
-  #    qsearch('cust_credit', { 'custnum' => $self->custnum } )
-  #;
-  #foreach (@cust_credit) { $total += $_->credited; }
-  #$total, @cust_credit;
-}
-
-=item cust_pay
-
-Depreciated.  See the cust_bill_pay method.
-
-#Returns all payments (see L<FS::cust_pay>) for this invoice.
-
-=cut
-
-sub cust_pay {
-  use Carp;
-  croak "FS::cust_bill->cust_pay depreciated; see FS::cust_bill->cust_bill_pay";
-  #my $self = shift;
-  #sort { $a->_date <=> $b->_date }
-  #  qsearch( 'cust_pay', { 'invnum' => $self->invnum } )
-  #;
-}
-
-=item cust_bill_pay
-
-Returns all payment applications (see L<FS::cust_bill_pay>) for this invoice.
-
-=cut
-
-sub cust_bill_pay {
-  my $self = shift;
-  sort { $a->_date <=> $b->_date }
-    qsearch( 'cust_bill_pay', { 'invnum' => $self->invnum } );
-}
-
-=item cust_credited
-
-Returns all applied credits (see L<FS::cust_credit_bill>) for this invoice.
-
-=cut
-
-sub cust_credited {
-  my $self = shift;
-  sort { $a->_date <=> $b->_date }
-    qsearch( 'cust_credit_bill', { 'invnum' => $self->invnum } )
-  ;
-}
-
-=item tax
-
-Returns the tax amount (see L<FS::cust_bill_pkg>) for this invoice.
-
-=cut
-
-sub tax {
-  my $self = shift;
-  my $total = 0;
-  my @taxlines = qsearch( 'cust_bill_pkg', { 'invnum' => $self->invnum ,
-                                             'pkgnum' => 0 } );
-  foreach (@taxlines) { $total += $_->setup; }
-  $total;
-}
-
-=item owed
-
-Returns the amount owed (still outstanding) on this invoice, which is charged
-minus all payment applications (see L<FS::cust_bill_pay>) and credit
-applications (see L<FS::cust_credit_bill>).
-
-=cut
-
-sub owed {
-  my $self = shift;
-  my $balance = $self->charged;
-  $balance -= $_->amount foreach ( $self->cust_bill_pay );
-  $balance -= $_->amount foreach ( $self->cust_credited );
-  $balance = sprintf( "%.2f", $balance);
-  $balance =~ s/^\-0\.00$/0.00/; #yay ieee fp
-  $balance;
-}
-
-=item send
-
-Sends this invoice to the destinations configured for this customer: send
-emails or print.  See L<FS::cust_main_invoice>.
-
-=cut
-
-sub send {
-  my($self,$template) = @_;
-  my @print_text = $self->print_text('', $template);
-  my @invoicing_list = $self->cust_main->invoicing_list;
-
-  if ( grep { $_ ne 'POST' } @invoicing_list ) { #email invoice
-    #false laziness w/FS::cust_pay::delete & fs_signup_server && ::realtime_card
-    #$ENV{SMTPHOSTS} = $smtpmachine;
-    $ENV{MAILADDRESS} = $invoice_from;
-    my $header = new Mail::Header ( [
-      "From: $invoice_from",
-      "To: ". join(', ', grep { $_ ne 'POST' } @invoicing_list ),
-      "Sender: $invoice_from",
-      "Reply-To: $invoice_from",
-      "Date: ". time2str("%a, %d %b %Y %X %z", time),
-      "Subject: Invoice",
-    ] );
-    my $message = new Mail::Internet (
-      'Header' => $header,
-      'Body' => [ @print_text ], #( date)
-    );
-    $!=0;
-    $message->smtpsend( Host => $smtpmachine )
-      or $message->smtpsend( Host => $smtpmachine, Debug => 1 )
-        or return "(customer # ". $self->custnum. ") can't send invoice email".
-                  " to ". join(', ', grep { $_ ne 'POST' } @invoicing_list ).
-                  " via server $smtpmachine with SMTP: $!";
-
-  }
-
-  if ( ! @invoicing_list || grep { $_ eq 'POST' } @invoicing_list ) { #postal
-    open(LPR, "|$lpr")
-      or return "Can't open pipe to $lpr: $!";
-    print LPR @print_text;
-    close LPR
-      or return $! ? "Error closing $lpr: $!"
-                   : "Exit status $? from $lpr";
-  }
-
-  '';
-
-}
-
-=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 Business::OnlinePayment realtime gateway.
-See http://search.cpan.org/search?mode=module&query=Business%3A%3AOnlinePayment
-for supproted processors.
-
-=cut
-
-sub realtime_card {
-  my $self = shift;
-  my $cust_main = $self->cust_main;
-  my $amount = $self->owed;
-
-  unless ( $processor =~ /^Business::OnlinePayment::(.*)$/ ) {
-    return "Real-time card processing not enabled (processor $processor)";
-  }
-  my $bop_processor = $1; #hmm?
-
-  my $address = $cust_main->address1;
-  $address .= ", ". $cust_main->address2 if $cust_main->address2;
-
-  #fix exp. date
-  #$cust_main->paydate =~ /^(\d+)\/\d*(\d{2})$/;
-  $cust_main->paydate =~ /^\d{2}(\d{2})[\/\-](\d+)[\/\-]\d+$/;
-  my $exp = "$2/$1";
-
-  my($payname, $payfirst, $paylast);
-  if ( $cust_main->payname ) {
-    $payname = $cust_main->payname;
-    $payname =~ /^\s*([\w \,\.\-\']*)?\s+([\w\,\.\-\']+)\s*$/
-      or do {
-              #$dbh->rollback if $oldAutoCommit;
-              return "Illegal payname $payname";
-            };
-    ($payfirst, $paylast) = ($1, $2);
-  } else {
-    $payfirst = $cust_main->getfield('first');
-    $paylast = $cust_main->getfield('last');
-    $payname =  "$payfirst $paylast";
-  }
-
-  my @invoicing_list = grep { $_ ne 'POST' } $cust_main->invoicing_list;
-  if ( $conf->exists('emailinvoiceauto')
-       || ( $conf->exists('emailinvoiceonly') && ! @invoicing_list ) ) {
-    push @invoicing_list, $cust_main->default_invoicing_list;
-  }
-  my $email = $invoicing_list[0];
-
-  my( $action1, $action2 ) = split(/\s*\,\s*/, $bop_action );
-
-  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 { $_->cust_pkg->part_pkg->pkg }
-        grep { $_->pkgnum } $self->cust_bill_pkg
-    );
-    $description = eval qq("$dtempl");
-
-  }
-  
-  my $transaction =
-    new Business::OnlinePayment( $bop_processor, @bop_options );
-  $transaction->content(
-    'type'           => 'CC',
-    'login'          => $bop_login,
-    'password'       => $bop_password,
-    'action'         => $action1,
-    'description'    => $description,
-    'amount'         => $amount,
-    'invoice_number' => $self->invnum,
-    'customer_id'    => $self->custnum,
-    'last_name'      => $paylast,
-    'first_name'     => $payfirst,
-    'name'           => $payname,
-    'address'        => $address,
-    'city'           => $cust_main->city,
-    'state'          => $cust_main->state,
-    'zip'            => $cust_main->zip,
-    'country'        => $cust_main->country,
-    'card_number'    => $cust_main->payinfo,
-    'expiration'     => $exp,
-    'referer'        => 'http://cleanwhisker.420.am/',
-    'email'          => $email,
-    'phone'          => $cust_main->daytime || $cust_main->night,
-  );
-  $transaction->submit();
-
-  if ( $transaction->is_success() && $action2 ) {
-    my $auth = $transaction->authorization;
-    my $ordernum = $transaction->order_number;
-
-    #warn "********* $auth ***********\n";
-    #warn "********* $ordernum ***********\n";
-    my $capture =
-      new Business::OnlinePayment( $bop_processor, @bop_options );
-
-    $capture->content(
-      action         => $action2,
-      login          => $bop_login,
-      password       => $bop_password,
-      order_number   => $ordernum,
-      amount         => $amount,
-      authorization  => $auth,
-      description    => $description,
-    );
-
-    $capture->submit();
-
-    unless ( $capture->is_success ) {
-      my $e = "Authorization sucessful but capture failed, invnum #".
-              $self->invnum. ': '.  $capture->result_code.
-              ": ". $capture->error_message;
-      warn $e;
-      return $e;
-    }
-
-  }
-
-  if ( $transaction->is_success() ) {
-
-    my $cust_pay = new FS::cust_pay ( {
-       'invnum'   => $self->invnum,
-       'paid'     => $amount,
-       '_date'     => '',
-       'payby'    => 'CARD',
-       'payinfo'  => $cust_main->payinfo,
-       'paybatch' => "$processor:". $transaction->authorization,
-    } );
-    my $error = $cust_pay->insert;
-    if ( $error ) {
-      # gah, even with transactions.
-      my $e = 'WARNING: Card debited but database not updated - '.
-              'error applying payment, invnum #' . $self->invnum.
-              " ($processor): $error";
-      warn $e;
-      return $e;
-    } else {
-      return '';
-    }
-  #} elsif ( $options{'report_badcard'} ) {
-  } else {
-
-    my $perror = "$processor error, invnum #". $self->invnum. ': '.
-                 $transaction->result_code. ": ". $transaction->error_message;
-
-    if ( $conf->exists('emaildecline')
-         && grep { $_ ne 'POST' } $cust_main->invoicing_list
-    ) {
-      my @templ = $conf->config('declinetemplate');
-      my $template = new Text::Template (
-        TYPE   => 'ARRAY',
-        SOURCE => [ map "$_\n", @templ ],
-      ) or return "($perror) can't create template: $Text::Template::ERROR";
-      $template->compile()
-        or return "($perror) can't compile template: $Text::Template::ERROR";
-
-      my $templ_hash = { error => $transaction->error_message };
-
-      #false laziness w/FS::cust_pay::delete & fs_signup_server && ::send
-      $ENV{MAILADDRESS} = $invoice_from;
-      my $header = new Mail::Header ( [
-        "From: $invoice_from",
-        "To: ". join(', ', grep { $_ ne 'POST' } $cust_main->invoicing_list ),
-        "Sender: $invoice_from",
-        "Reply-To: $invoice_from",
-        "Date: ". time2str("%a, %d %b %Y %X %z", time),
-        "Subject: Your credit card could not be processed",
-      ] );
-      my $message = new Mail::Internet (
-        'Header' => $header,
-        'Body' => [ $template->fill_in(HASH => $templ_hash) ],
-      );
-      $!=0;
-      $message->smtpsend( Host => $smtpmachine )
-        or $message->smtpsend( Host => $smtpmachine, Debug => 1 )
-          or return "($perror) (customer # ". $self->custnum.
-            ") can't send card decline email to ".
-            join(', ', grep { $_ ne 'POST' } $cust_main->invoicing_list ).
-            " via server $smtpmachine with SMTP: $!";
-    }
-  
-    return $perror;
-  }
-
-}
-
-=item realtime_card_cybercash
-
-Attempts to pay this invoice with the CyberCash CashRegister realtime gateway.
-
-=cut
-
-sub realtime_card_cybercash {
-  my $self = shift;
-  my $cust_main = $self->cust_main;
-  my $amount = $self->owed;
-
-  return "CyberCash CashRegister real-time card processing not enabled!"
-    unless $processor eq 'cybercash3.2';
-
-  my $address = $cust_main->address1;
-  $address .= ", ". $cust_main->address2 if $cust_main->address2;
-
-  #fix exp. date
-  #$cust_main->paydate =~ /^(\d+)\/\d*(\d{2})$/;
-  $cust_main->paydate =~ /^\d{2}(\d{2})[\/\-](\d+)[\/\-]\d+$/;
-  my $exp = "$2/$1";
-
-  #
-
-  my $paybatch = $self->invnum. 
-                  '-' . time2str("%y%m%d%H%M%S", time);
-
-  my $payname = $cust_main->payname ||
-                $cust_main->getfield('first').' '.$cust_main->getfield('last');
-
-  my $country = $cust_main->country eq 'US' ? 'USA' : $cust_main->country;
-
-  my @full_xaction = ( $xaction,
-    'Order-ID'     => $paybatch,
-    'Amount'       => "usd $amount",
-    'Card-Number'  => $cust_main->getfield('payinfo'),
-    'Card-Name'    => $payname,
-    'Card-Address' => $address,
-    'Card-City'    => $cust_main->getfield('city'),
-    'Card-State'   => $cust_main->getfield('state'),
-    'Card-Zip'     => $cust_main->getfield('zip'),
-    'Card-Country' => $country,
-    'Card-Exp'     => $exp,
-  );
-
-  my %result;
-  %result = &CCMckDirectLib3_2::SendCC2_1Server(@full_xaction);
-  
-  if ( $result{'MStatus'} eq 'success' ) { #cybercash smps v.2 or 3
-    my $cust_pay = new FS::cust_pay ( {
-       'invnum'   => $self->invnum,
-       'paid'     => $amount,
-       '_date'     => '',
-       'payby'    => 'CARD',
-       'payinfo'  => $cust_main->payinfo,
-       'paybatch' => "$processor:$paybatch",
-    } );
-    my $error = $cust_pay->insert;
-    if ( $error ) {
-      # gah, even with transactions.
-      my $e = 'WARNING: Card debited but database not updated - '.
-              'error applying payment, invnum #' . $self->invnum.
-              " (CyberCash Order-ID $paybatch): $error";
-      warn $e;
-      return $e;
-    } else {
-      return '';
-    }
-#  } elsif ( $result{'Mstatus'} ne 'failure-bad-money'
-#            || $options{'report_badcard'}
-#          ) {
-  } else {
-     return 'Cybercash error, invnum #' . 
-       $self->invnum. ':'. $result{'MErrMsg'};
-  }
-
-}
-
-=item batch_card
-
-Adds a payment for this invoice to the pending credit card batch (see
-L<FS::cust_pay_batch>).
-
-=cut
-
-sub batch_card {
-  my $self = shift;
-  my $cust_main = $self->cust_main;
-
-  my $cust_pay_batch = new FS::cust_pay_batch ( {
-    'invnum'   => $self->getfield('invnum'),
-    'custnum'  => $cust_main->getfield('custnum'),
-    'last'     => $cust_main->getfield('last'),
-    'first'    => $cust_main->getfield('first'),
-    'address1' => $cust_main->getfield('address1'),
-    'address2' => $cust_main->getfield('address2'),
-    'city'     => $cust_main->getfield('city'),
-    'state'    => $cust_main->getfield('state'),
-    'zip'      => $cust_main->getfield('zip'),
-    'country'  => $cust_main->getfield('country'),
-    'trancode' => 77,
-    'cardnum'  => $cust_main->getfield('payinfo'),
-    'exp'      => $cust_main->getfield('paydate'),
-    'payname'  => $cust_main->getfield('payname'),
-    'amount'   => $self->owed,
-  } );
-  my $error = $cust_pay_batch->insert;
-  die $error if $error;
-
-  '';
-}
-
-=item print_text [TIME];
-
-Returns an text invoice, as a list of lines.
-
-TIME an optional 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.
-
-=cut
-
-sub print_text {
-
-  my( $self, $today, $template ) = @_;
-  $today ||= time;
-#  my $invnum = $self->invnum;
-  my $cust_main = qsearchs('cust_main', { 'custnum', $self->custnum } );
-  $cust_main->payname( $cust_main->first. ' '. $cust_main->getfield('last') )
-    unless $cust_main->payname;
-
-  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;
-
-  #my @collect = ();
-  #my($description,$amount);
-  @buf = ();
-
-  #previous balance
-  foreach ( @pr_cust_bill ) {
-    push @buf, [
-      "Previous Balance, Invoice #". $_->invnum. 
-                 " (". time2str("%x",$_->_date). ")",
-      $money_char. sprintf("%10.2f",$_->owed)
-    ];
-  }
-  if (@pr_cust_bill) {
-    push @buf,['','-----------'];
-    push @buf,[ 'Total Previous Balance',
-                $money_char. sprintf("%10.2f",$pr_total ) ];
-    push @buf,['',''];
-  }
-
-  #new charges
-  foreach ( $self->cust_bill_pkg ) {
-
-    if ( $_->pkgnum ) {
-
-      my($cust_pkg)=qsearchs('cust_pkg', { 'pkgnum', $_->pkgnum } );
-      my($part_pkg)=qsearchs('part_pkg',{'pkgpart'=>$cust_pkg->pkgpart});
-      my($pkg)=$part_pkg->pkg;
-
-      if ( $_->setup != 0 ) {
-        push @buf, [ "$pkg Setup", $money_char. sprintf("%10.2f",$_->setup) ];
-        push @buf,
-          map { [ "  ". $_->[0]. ": ". $_->[1], '' ] } $cust_pkg->labels;
-      }
-
-      if ( $_->recur != 0 ) {
-        push @buf, [
-          "$pkg (" . time2str("%x",$_->sdate) . " - " .
-                                time2str("%x",$_->edate) . ")",
-          $money_char. sprintf("%10.2f",$_->recur)
-        ];
-        push @buf,
-          map { [ "  ". $_->[0]. ": ". $_->[1], '' ] } $cust_pkg->labels;
-      }
-
-    } else { #pkgnum Tax
-      push @buf,["Tax", $money_char. sprintf("%10.2f",$_->setup) ] 
-        if $_->setup != 0;
-    }
-  }
-
-  push @buf,['','-----------'];
-  push @buf,['Total New Charges',
-             $money_char. sprintf("%10.2f",$self->charged) ];
-  push @buf,['',''];
-
-  push @buf,['','-----------'];
-  push @buf,['Total Charges',
-             $money_char. sprintf("%10.2f",$self->charged + $pr_total) ];
-  push @buf,['',''];
-
-  #credits
-  foreach ( $self->cust_credited ) {
-
-    #something more elaborate if $_->amount ne $_->cust_credit->credited ?
-
-    my $reason = substr($_->cust_credit->reason,0,32);
-    $reason .= '...' if length($reason) < length($_->cust_credit->reason);
-    $reason = " ($reason) " if $reason;
-    push @buf,[
-      "Credit #". $_->crednum. " (". time2str("%x",$_->cust_credit->_date) .")".
-        $reason,
-      $money_char. sprintf("%10.2f",$_->amount)
-    ];
-  }
-  #foreach ( @cr_cust_credit ) {
-  #  push @buf,[
-  #    "Credit #". $_->crednum. " (" . time2str("%x",$_->_date) .")",
-  #    $money_char. sprintf("%10.2f",$_->credited)
-  #  ];
-  #}
-
-  #get & print payments
-  foreach ( $self->cust_bill_pay ) {
-
-    #something more elaborate if $_->amount ne ->cust_pay->paid ?
-
-    push @buf,[
-      "Payment received ". time2str("%x",$_->cust_pay->_date ),
-      $money_char. sprintf("%10.2f",$_->amount )
-    ];
-  }
-
-  #balance due
-  push @buf,['','-----------'];
-  push @buf,['Balance Due', $money_char. 
-    sprintf("%10.2f", $balance_due ) ];
-
-  #create the template
-  my $templatefile = 'invoice_template';
-  $templatefile .= "_$template" if $template;
-  my @invoice_template = $conf->config($templatefile)
-  or die "cannot load config file $templatefile";
-  $invoice_lines = 0;
-  my $wasfunc = 0;
-  foreach ( grep /invoice_lines\(\d+\)/, @invoice_template ) { #kludgy
-    /invoice_lines\((\d+)\)/;
-    $invoice_lines += $1;
-    $wasfunc=1;
-  }
-  die "no invoice_lines() functions in template?" unless $wasfunc;
-  my $invoice_template = new Text::Template (
-    TYPE   => 'ARRAY',
-    SOURCE => [ map "$_\n", @invoice_template ],
-  ) or die "can't create new Text::Template object: $Text::Template::ERROR";
-  $invoice_template->compile()
-    or die "can't compile template: $Text::Template::ERROR";
-
-  #setup template variables
-  package FS::cust_bill::_template; #!
-  use vars qw( $invnum $date $page $total_pages @address $overdue @buf );
-
-  $invnum = $self->invnum;
-  $date = $self->_date;
-  $page = 1;
-
-  if ( $FS::cust_bill::invoice_lines ) {
-    $total_pages =
-      int( scalar(@FS::cust_bill::buf) / $FS::cust_bill::invoice_lines );
-    $total_pages++
-      if scalar(@FS::cust_bill::buf) % $FS::cust_bill::invoice_lines;
-  } else {
-    $total_pages = 1;
-  }
-
-  #format address (variable for the template)
-  my $l = 0;
-  @address = ( '', '', '', '', '', '' );
-  package FS::cust_bill; #!
-  $FS::cust_bill::_template::address[$l++] =
-    $cust_main->payname.
-      ( ( $cust_main->payby eq 'BILL' ) && $cust_main->payinfo
-        ? " (P.O. #". $cust_main->payinfo. ")"
-        : ''
-      )
-  ;
-  $FS::cust_bill::_template::address[$l++] = $cust_main->company
-    if $cust_main->company;
-  $FS::cust_bill::_template::address[$l++] = $cust_main->address1;
-  $FS::cust_bill::_template::address[$l++] = $cust_main->address2
-    if $cust_main->address2;
-  $FS::cust_bill::_template::address[$l++] =
-    $cust_main->city. ", ". $cust_main->state. "  ".  $cust_main->zip;
-  $FS::cust_bill::_template::address[$l++] = $cust_main->country
-    unless $cust_main->country eq 'US';
-
-       #  #overdue? (variable for the template)
-       #  $FS::cust_bill::_template::overdue = ( 
-       #    $balance_due > 0
-       #    && $today > $self->_date 
-       ##    && $self->printed > 1
-       #    && $self->printed > 0
-       #  );
-
-  #and subroutine for the template
-
-  sub FS::cust_bill::_template::invoice_lines {
-    my $lines = shift or return @buf;
-    map { 
-      scalar(@buf) ? shift @buf : [ '', '' ];
-    }
-    ( 1 .. $lines );
-  }
-
-
-  #and fill it in
-  $FS::cust_bill::_template::page = 1;
-  my $lines;
-  my @collect;
-  while (@buf) {
-    push @collect, split("\n",
-      $invoice_template->fill_in( PACKAGE => 'FS::cust_bill::_template' )
-    );
-    $FS::cust_bill::_template::page++;
-  }
-
-  map "$_\n", @collect;
-
-}
-
-=back
-
-=head1 VERSION
-
-$Id: cust_bill.pm,v 1.38 2002-06-26 02:37:48 ivan Exp $
-
-=head1 BUGS
-
-The delete method.
-
-print_text formatting (and some logic :/) is in source, but needs to be
-slurped in from a file.  Also number of lines ($=).
-
-missing print_ps for a nice postscript copy (maybe HylaFAX-cover-page-style
-or something similar so the look can be completely customized?)
-
-=head1 SEE ALSO
-
-L<FS::Record>, L<FS::cust_main>, L<FS::cust_bill_pay>, L<FS::cust_pay>,
-L<FS::cust_bill_pkg>, L<FS::cust_bill_credit>, schema.html from the base
-documentation.
-
-=cut
-
-1;
-