send_ftp doc fix
[freeside.git] / FS / FS / cust_bill.pm
index a419ca8..52fc942 100644 (file)
@@ -8,9 +8,10 @@ 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;
+use Mail::Internet 1.44;
 use Mail::Header;
 use Text::Template;
+use FS::UID qw( datasrc );
 use FS::Record qw( qsearch qsearchs );
 use FS::cust_main;
 use FS::cust_bill_pkg;
@@ -369,9 +370,9 @@ emails or print.  See L<FS::cust_main_invoice>.
 
 sub send {
   my($self,$template) = @_;
-
-  #my @print_text = $cust_bill->print_text; #( date )
+  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;
@@ -386,7 +387,7 @@ sub send {
     ] );
     my $message = new Mail::Internet (
       'Header' => $header,
-      'Body' => [ $self->print_text('', $template) ], #( date)
+      'Body' => [ @print_text ], #( date)
     );
     $!=0;
     $message->smtpsend( Host => $smtpmachine )
@@ -395,11 +396,12 @@ sub send {
                   " to ". join(', ', grep { $_ ne 'POST' } @invoicing_list ).
                   " via server $smtpmachine with SMTP: $!";
 
-  #} elsif ( grep { $_ eq 'POST' } @invoicing_list ) {
-  } elsif ( ! @invoicing_list || grep { $_ eq 'POST' } @invoicing_list ) {
+  }
+
+  if ( ! @invoicing_list || grep { $_ eq 'POST' } @invoicing_list ) { #postal
     open(LPR, "|$lpr")
       or return "Can't open pipe to $lpr: $!";
-    print LPR $self->print_text; #( date )
+    print LPR @print_text;
     close LPR
       or return $! ? "Error closing $lpr: $!"
                    : "Exit status $? from $lpr";
@@ -409,6 +411,170 @@ sub send {
 
 }
 
+=item send_csv OPTIONS
+
+Sends invoice as a CSV data-file to a remote host with the specified protocol.
+
+Options are:
+
+protocol - currently only "ftp"
+server
+username
+password
+dir
+
+The file will be named "N-YYYYMMDDHHMMSS.csv" where N is the invoice number
+and YYMMDDHHMMSS is a timestamp.
+
+The fields of the CSV file is as follows:
+
+record_type, invnum, custnum, _date, charged, first, last, company, address1, address2, city, state, zip, country, pkg, setup, recur, sdate, edate
+
+=over 4
+
+=item record type - B<record_type> is either C<cust_bill> or C<cust_bill_pkg>
+
+If B<record_type> is C<cust_bill>, this is a primary invoice record.  The
+last five fields (B<pkg> through B<edate>) are irrelevant, and all other
+fields are filled in.
+
+If B<record_type> is C<cust_bill_pkg>, this is a line item record.  Only the
+first two fields (B<record_type> and B<invnum>) and the last five fields
+(B<pkg> through B<edate>) are filled in.
+
+=item invnum - invoice number
+
+=item custnum - customer number
+
+=item _date - invoice date
+
+=item charged - total invoice amount
+
+=item first - customer first name
+
+=item last - customer first name
+
+=item company - company name
+
+=item address1 - address line 1
+
+=item address2 - address line 1
+
+=item city
+
+=item state
+
+=item zip
+
+=item country
+
+=item pkg - line item description
+
+=item setup - line item setup fee (one or both of B<setup> and B<recur> will be defined)
+
+=item recur - line item recurring fee (one or both of B<setup> and B<recur> will be defined)
+
+=item sdate - start date for recurring fee
+
+=item edate - end date for recurring fee
+
+=back
+
+=cut
+
+sub send_csv {
+  my($self, %opt) = @_;
+
+  #part one: create file
+
+  my $spooldir = "/usr/local/etc/freeside/export.". datasrc. "/cust_bill";
+  mkdir $spooldir, 0700 unless -d $spooldir;
+
+  my $file = $spooldir. '/'. $self->invnum. time2str('-%Y%m%d%H%M%S.csv', time);
+
+  open(CSV, ">$file") or die "can't open $file: $!";
+
+  eval "use Text::CSV_XS";
+  die $@ if $@;
+
+  my $csv = Text::CSV_XS->new({'always_quote'=>1});
+
+  my $cust_main = $self->cust_main;
+
+  $csv->combine(
+    'cust_bill',
+    $self->invnum,
+    $self->custnum,
+    time2str("%x", $self->_date),
+    sprintf("%.2f", $self->charged),
+    ( map { $cust_main->getfield($_) }
+        qw( first last company address1 address2 city state zip country ) ),
+    map { '' } (1..5),
+  ) or die "can't create csv";
+  print CSV $csv->string. "\n";
+
+  #new charges (false laziness w/print_text)
+  foreach my $cust_bill_pkg ( $self->cust_bill_pkg ) {
+
+    my($pkg, $setup, $recur, $sdate, $edate);
+    if ( $cust_bill_pkg->pkgnum ) {
+    
+      ($pkg, $setup, $recur, $sdate, $edate) = (
+        $cust_bill_pkg->cust_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 )
+          : '' ),
+        time2str("%x", $cust_bill_pkg->sdate),
+        time2str("%x", $cust_bill_pkg->edate),
+      );
+
+    } else { #pkgnum Tax
+      next unless $cust_bill_pkg->setup != 0;
+      ($pkg, $setup, $recur, $sdate, $edate) =
+        ( 'Tax', sprintf("%10.2f",$cust_bill_pkg->setup), '', '', '' );
+    }
+
+    $csv->combine(
+      'cust_bill_pkg',
+      $self->invnum,
+      ( map { '' } (1..11) ),
+      ($pkg, $setup, $recur, $sdate, $edate)
+    ) or die "can't create csv";
+    print CSV $csv->string. "\n";
+
+  }
+
+  close CSV or die "can't close CSV: $!";
+
+  #part two: upload it
+
+  my $net;
+  if ( $opt{protocol} eq 'ftp' ) {
+    eval "use Net::FTP;";
+    die $@ if $@;
+    $net = Net::FTP->new($opt{server}) or die @$;
+  } else {
+    die "unknown protocol: $opt{protocol}";
+  }
+
+  $net->login( $opt{username}, $opt{password} )
+    or die "can't FTP to $opt{username}\@$opt{server}: login error: $@";
+
+  $net->binary or die "can't set binary mode";
+
+  $net->cwd($opt{dir}) or die "can't cwd to $opt{dir}";
+
+  $net->put($file) or die "can't put $file: $!";
+
+  $net->quit;
+
+  unlink $file;
+
+}
+
 =item comp
 
 Pays this invoice with a compliemntary payment.  If there is an error,
@@ -458,7 +624,7 @@ sub realtime_card {
   my($payname, $payfirst, $paylast);
   if ( $cust_main->payname ) {
     $payname = $cust_main->payname;
-    $payname =~ /^\s*([\w \,\.\-\']*)?\s+([\w\,\.\-\']+)$/
+    $payname =~ /^\s*([\w \,\.\-\']*)?\s+([\w\,\.\-\']+)\s*$/
       or do {
               #$dbh->rollback if $oldAutoCommit;
               return "Illegal payname $payname";
@@ -466,14 +632,14 @@ sub realtime_card {
     ($payfirst, $paylast) = ($1, $2);
   } else {
     $payfirst = $cust_main->getfield('first');
-    $paylast = $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;
+    push @invoicing_list, $cust_main->all_emails;
   }
   my $email = $invoicing_list[0];
 
@@ -518,18 +684,23 @@ sub realtime_card {
     '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;
+    my $ordernum = $transaction->can('order_number')
+                   ? $transaction->order_number
+                   : '';
+
     #warn "********* $auth ***********\n";
     #warn "********* $ordernum ***********\n";
     my $capture =
       new Business::OnlinePayment( $bop_processor, @bop_options );
 
-    $capture->content(
+    my %capture = (
+      type           => 'CC',
       action         => $action2,
       login          => $bop_login,
       password       => $bop_password,
@@ -537,8 +708,18 @@ sub realtime_card {
       amount         => $amount,
       authorization  => $auth,
       description    => $description,
+      card_number    => $cust_main->payinfo,
+      expiration     => $exp,
     );
 
+    foreach my $field (qw( authorization_source_code returned_ACI                                          transaction_identifier validation_code           
+                           transaction_sequence_num local_transaction_date    
+                           local_transaction_time AVS_result_code          )) {
+      $capture{$field} = $transaction->$field() if $transaction->can($field);
+    }
+
+    $capture->content( %capture );
+
     $capture->submit();
 
     unless ( $capture->is_success ) {
@@ -589,7 +770,7 @@ sub realtime_card {
       $template->compile()
         or return "($perror) can't compile template: $Text::Template::ERROR";
 
-      my $error = $transaction->error_message;
+      my $templ_hash = { error => $transaction->error_message };
 
       #false laziness w/FS::cust_pay::delete & fs_signup_server && ::send
       $ENV{MAILADDRESS} = $invoice_from;
@@ -603,7 +784,7 @@ sub realtime_card {
       ] );
       my $message = new Mail::Internet (
         'Header' => $header,
-        'Body' => [ $template->fill_in() ],
+        'Body' => [ $template->fill_in(HASH => $templ_hash) ],
       );
       $!=0;
       $message->smtpsend( Host => $smtpmachine )
@@ -725,8 +906,10 @@ sub batch_card {
     'payname'  => $cust_main->getfield('payname'),
     'amount'   => $self->owed,
   } );
-  $cust_pay_batch->insert;
+  my $error = $cust_pay_batch->insert;
+  die $error if $error;
 
+  '';
 }
 
 =item print_text [TIME];
@@ -947,7 +1130,7 @@ sub print_text {
 
 =head1 VERSION
 
-$Id: cust_bill.pm,v 1.32 2002-04-16 22:56:58 ivan Exp $
+$Id: cust_bill.pm,v 1.44 2002-09-17 00:40:07 ivan Exp $
 
 =head1 BUGS