billing events!
authorivan <ivan>
Mon, 4 Feb 2002 16:44:48 +0000 (16:44 +0000)
committerivan <ivan>
Mon, 4 Feb 2002 16:44:48 +0000 (16:44 +0000)
FS/FS/cust_bill.pm
FS/FS/cust_main.pm
httemplate/docs/install.html
httemplate/docs/upgrade8.html
httemplate/edit/part_bill_event.cgi
httemplate/view/cust_bill.cgi

index 8b326a5..00135af 100644 (file)
@@ -2,8 +2,14 @@ package FS::cust_bill;
 
 use strict;
 use vars qw( @ISA $conf $invoice_template $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;
+use Mail::Header;
 use Text::Template;
 use FS::Record qw( qsearch qsearchs );
 use FS::cust_main;
@@ -12,6 +18,7 @@ use FS::cust_credit;
 use FS::cust_pay;
 use FS::cust_pkg;
 use FS::cust_credit_bill;
+use FS::cust_pay_batch;
 
 @ISA = qw( FS::Record );
 
@@ -36,6 +43,44 @@ $FS::UID::callback{'FS::cust_bill'} = sub {
   ) or die "can't create new Text::Template object: $Text::Template::ERROR";
   $invoice_template->compile()
     or die "can't compile template: $Text::Template::ERROR";
+
+  $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
@@ -88,8 +133,7 @@ L<Time::Local> and L<Date::Parse> for conversion functions.
 
 =item charged - amount of this invoice
 
-=item printed - how many times this invoice has been printed automatically
-(see L<FS::cust_main/"collect">).
+=item printed - deprecated
 
 =item closed - books closed flag, empty or `Y'
 
@@ -207,6 +251,17 @@ sub cust_bill_pkg {
   qsearch( 'cust_bill_pkg', { '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.
@@ -306,6 +361,315 @@ sub owed {
   $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 = shift;
+
+  #my @print_text = $cust_bill->print_text; #( date )
+  my @invoicing_list = $self->cust_main->invoicing_list;
+  if ( grep { $_ ne 'POST' } @invoicing_list ) { #email invoice
+    $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' => [ $self->print_text ], #( date)
+    );
+    $message->smtpsend
+      or return "Can't send invoice email to server $smtpmachine!";
+
+  #} elsif ( grep { $_ eq 'POST' } @invoicing_list ) {
+  } elsif ( ! @invoicing_list || grep { $_ eq 'POST' } @invoicing_list ) {
+    open(LPR, "|$lpr")
+      or return "Can't open pipe to $lpr: $!";
+    print LPR $self->print_text; #( date )
+    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 \,\.\-\']*\w)?\s+([\w\,\.\-\']+)$/
+      or do {
+              #$dbh->rollback if $oldAutoCommit;
+              return "Illegal payname $payname";
+            };
+    ($payfirst, $paylast) = ($1, $2);
+  } else {
+    $payfirst = $cust_main->getfield('first');
+    $paylast = $cust_main->getfield('first');
+    $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 $transaction =
+    new Business::OnlinePayment( $bop_processor, @bop_options );
+  $transaction->content(
+    'type'           => 'CC',
+    'login'          => $bop_login,
+    'password'       => $bop_password,
+    'action'         => $action1,
+    'description'    => 'Internet Services',
+    '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,
+  );
+  $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    => 'Internet Services',
+    );
+
+    $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 {
+    return "$processor error, invnum #". $self->invnum. ': '.
+           $transaction->result_code. ": ". $transaction->error_message;
+  }
+
+}
+
+=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,
+  } );
+  $cust_pay_batch->insert;
+
+}
+
 =item print_text [TIME];
 
 Returns an text invoice, as a list of lines.
@@ -500,7 +864,7 @@ sub print_text {
 
 =head1 VERSION
 
-$Id: cust_bill.pm,v 1.15 2002-01-28 06:57:23 ivan Exp $
+$Id: cust_bill.pm,v 1.16 2002-02-04 16:44:48 ivan Exp $
 
 =head1 BUGS
 
index 8a7a6f8..62f61a6 100644 (file)
@@ -1,16 +1,12 @@
 package FS::cust_main;
 
 use strict;
-use vars qw( @ISA $conf $lpr $processor $xaction $E_NoErr $invoice_from
-             $smtpmachine $Debug $bop_processor $bop_login $bop_password
-             $bop_action @bop_options $import );
+use vars qw( @ISA $conf $Debug $import );
 use Safe;
 use Carp;
 use Time::Local;
 use Date::Format;
 #use Date::Manip;
-use Mail::Internet;
-use Mail::Header;
 use Business::CreditCard;
 use FS::UID qw( getotaker dbh );
 use FS::Record qw( qsearchs qsearch dbdef );
@@ -19,7 +15,6 @@ use FS::cust_bill;
 use FS::cust_bill_pkg;
 use FS::cust_pay;
 use FS::cust_credit;
-use FS::cust_pay_batch;
 use FS::part_referral;
 use FS::cust_main_county;
 use FS::agent;
@@ -29,6 +24,8 @@ use FS::cust_bill_pay;
 use FS::prepay_credit;
 use FS::queue;
 use FS::part_pkg;
+use FS::part_bill_event;
+use FS::cust_bill_event;
 
 @ISA = qw( FS::Record );
 
@@ -40,42 +37,7 @@ $import = 0;
 #ask FS::UID to run this stuff for us later
 $FS::UID::callback{'FS::cust_main'} = sub { 
   $conf = new FS::Conf;
-  $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";
-  }
+  #yes, need it for stuff below (prolly should be cached)
 };
 
 sub _cache {
@@ -385,7 +347,8 @@ will be deleted.  Did I mention that this is NOT what you want when a customer
 cancels service and that you really should be looking see L<FS::cust_pkg/cancel>?
 
 You can't delete a customer with invoices (see L<FS::cust_bill>),
-or credits (see L<FS::cust_credit>) or payments (see L<FS::cust_pay>).
+or credits (see L<FS::cust_credit>), payments (see L<FS::cust_pay>) or
+refunds (see L<FS::cust_refund>).
 
 =cut
 
@@ -415,6 +378,10 @@ sub delete {
     $dbh->rollback if $oldAutoCommit;
     return "Can't delete a customer with payments";
   }
+  if ( qsearch( 'cust_refund', { 'custnum' => $self->custnum } ) ) {
+    $dbh->rollback if $oldAutoCommit;
+    return "Can't delete a customer with refunds";
+  }
 
   my @cust_pkg = $self->ncancelled_pkgs;
   if ( @cust_pkg ) {
@@ -443,7 +410,7 @@ sub delete {
     }
   }
 
-  foreach my $cust_main_invoice (
+  foreach my $cust_main_invoice ( #(email invoice destinations, not invoices)
     qsearch( 'cust_main_invoice', { 'custnum' => $self->custnum } )
   ) {
     my $error = $cust_main_invoice->delete;
@@ -1082,6 +1049,9 @@ L<FS::cust_bill>).  Usually used after the bill method.
 Depending on the value of `payby', this may print an invoice (`BILL'), charge
 a credit card (`CARD'), or just add any necessary (pseudo-)payment (`COMP').
 
+Most actions are now triggered by invoice events; see L<FS::part_bill_event>
+and the invoice events web interface.
+
 If there is an error, returns the error, otherwise returns false.
 
 Options are passed as name-value pairs.
@@ -1092,15 +1062,12 @@ invoice_time - Use this time when deciding when to print invoices and
 late notices on those invoices.  The default is now.  It is specified as a UNIX timestamp; see L<perlfunc/"time">).  Also see L<Time::Local> and L<Date::Parse>
 for conversion functions.
 
-batch_card - Set this true to batch cards (see L<FS::cust_pay_batch>).  By
-default, cards are processed immediately, which will generate an error if
-CyberCash is not installed.
+batch_card - This option is deprecated.  See the invoice events web interface
+to control whether cards are batched or run against a realtime gateway.
 
-report_badcard - Set this true if you want bad card transactions to
-return an error.  By default, they don't.
+report_badcard - This option is deprecated.
 
-force_print - force printing even if invoice has been printed more than once
-every 30 days, and don't increment the `printed' field.
+force_print - This option is deprecated; see the invoice events web interface.
 
 =cut
 
@@ -1141,306 +1108,62 @@ sub collect {
     next unless $cust_bill->owed > 0;
 
     # don't try to charge for the same invoice if it's already in a batch
-    next if qsearchs( 'cust_pay_batch', { 'invnum' => $cust_bill->invnum } );
+    #next if qsearchs( 'cust_pay_batch', { 'invnum' => $cust_bill->invnum } );
 
     warn "invnum ". $cust_bill->invnum. " (owed ". $cust_bill->owed. ", amount $amount, balance $balance)" if $Debug;
 
     next unless $amount > 0;
 
-    if ( $self->payby eq 'BILL' ) {
-
-      #30 days 2592000
-      my $since = $invoice_time - ( $cust_bill->_date || 0 );
-      #warn "$invoice_time ", $cust_bill->_date, " $since";
-      if ( $since >= 0 #don't print future invoices
-           && ( ( $cust_bill->printed * 2592000 ) <= $since
-                || $options{'force_print'} )
-      ) {
-
-        #my @print_text = $cust_bill->print_text; #( date )
-        my @invoicing_list = $self->invoicing_list;
-        if ( grep { $_ ne 'POST' } @invoicing_list ) { #email invoice
-          $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' => [ $cust_bill->print_text ], #( date)
-          );
-          $message->smtpsend or die "Can't send invoice email!"; #die?  warn?
-
-        } elsif ( ! @invoicing_list || grep { $_ eq 'POST' } @invoicing_list ) {
-          open(LPR, "|$lpr") or die "Can't open pipe to $lpr: $!";
-          print LPR $cust_bill->print_text; #( date )
-          close LPR
-            or die $! ? "Error closing $lpr: $!"
-                         : "Exit status $? from $lpr";
-        }
-
-        unless ( $options{'force_print'} ) {
-          my %hash = $cust_bill->hash;
-          $hash{'printed'}++;
-          my $new_cust_bill = new FS::cust_bill(\%hash);
-          my $error = $new_cust_bill->replace($cust_bill);
-          warn "Error updating $cust_bill->printed: $error" if $error;
-        }
-
-      }
+    foreach my $part_bill_event (
+      sort {    $a->seconds   <=> $b->seconds
+             || $a->weight    <=> $b->weight
+             || $a->eventpart <=> $b->eventpart }
+        grep { $_->seconds > ( $invoice_time - ( $cust_bill->_date || 0 ) )
+               && ! qsearchs( 'cust_bill_event', {
+                                'invnum'    => $cust_bill->invnum,
+                                'eventpart' => $_->eventpart       } )
+             }
+          qsearch('part_bill_event', { 'payby'    => $self->payby,
+                                       'disabled' => '',           } )
+    ) {
+      #run callback
+      my $cust_main = $self; #for callback
+      my $error = eval $part_bill_event->eventcode;
 
-    } elsif ( $self->payby eq 'COMP' ) {
-      my $cust_pay = new FS::cust_pay ( {
-         'invnum' => $cust_bill->invnum,
-         'paid' => $amount,
-         '_date' => '',
-         'payby' => 'COMP',
-         'payinfo' => $self->payinfo,
-         'paybatch' => ''
-      } );
-      my $error = $cust_pay->insert;
       if ( $error ) {
-        $dbh->rollback if $oldAutoCommit;
-        return 'Error COMPing invnum #'. $cust_bill->invnum. ": $error";
-      }
-
 
-    } elsif ( $self->payby eq 'CARD' ) {
+        warn "Error running invoice event (". $part_bill_event->eventcode.
+             "): $error";
 
-      if ( $options{'batch_card'} ne 'yes' ) {
+      } else {
 
-        unless ( $processor ) {
-          $dbh->rollback if $oldAutoCommit;
-          return "Real time card processing not enabled!";
-        }
-
-        my $address = $self->address1;
-        $address .= ", ". $self->address2 if $self->address2;
-
-        #fix exp. date
-        #$self->paydate =~ /^(\d+)\/\d*(\d{2})$/;
-        $self->paydate =~ /^\d{2}(\d{2})[\/\-](\d+)[\/\-]\d+$/;
-        my $exp = "$2/$1";
-
-        if ( $processor eq 'cybercash3.2' ) {
-
-          #fix exp. date for cybercash
-          #$self->paydate =~ /^(\d+)\/\d*(\d{2})$/;
-          $self->paydate =~ /^\d{2}(\d{2})[\/\-](\d+)[\/\-]\d+$/;
-          my $exp = "$2/$1";
-
-          my $paybatch = $cust_bill->invnum. 
-                         '-' . time2str("%y%m%d%H%M%S", time);
-
-          my $payname = $self->payname ||
-                        $self->getfield('first'). ' '. $self->getfield('last');
-
-
-          my $country = $self->country eq 'US' ? 'USA' : $self->country;
-
-          my @full_xaction = ( $xaction,
-            'Order-ID'     => $paybatch,
-            'Amount'       => "usd $amount",
-            'Card-Number'  => $self->getfield('payinfo'),
-            'Card-Name'    => $payname,
-            'Card-Address' => $address,
-            'Card-City'    => $self->getfield('city'),
-            'Card-State'   => $self->getfield('state'),
-            'Card-Zip'     => $self->getfield('zip'),
-            'Card-Country' => $country,
-            'Card-Exp'     => $exp,
-          );
-
-          my %result;
-          %result = &CCMckDirectLib3_2::SendCC2_1Server(@full_xaction);
-         
-          #if ( $result{'MActionCode'} == 7 ) { #cybercash smps v.1.1.3
-          #if ( $result{'action-code'} == 7 ) { #cybercash smps v.2.1
-          if ( $result{'MStatus'} eq 'success' ) { #cybercash smps v.2 or 3
-            my $cust_pay = new FS::cust_pay ( {
-               'invnum'   => $cust_bill->invnum,
-               'paid'     => $amount,
-               '_date'     => '',
-               'payby'    => 'CARD',
-               'payinfo'  => $self->payinfo,
-               'paybatch' => "$processor:$paybatch",
-            } );
-            my $error = $cust_pay->insert;
-            if ( $error ) {
-              # gah, even with transactions.
-              $dbh->commit if $oldAutoCommit; #well.
-              my $e = 'WARNING: Card debited but database not updated - '.
-                      'error applying payment, invnum #' . $cust_bill->invnum.
-                      " (CyberCash Order-ID $paybatch): $error";
-              warn $e;
-              return $e;
-            }
-          } elsif ( $result{'Mstatus'} ne 'failure-bad-money'
-                 || $options{'report_badcard'} ) {
-             $dbh->commit if $oldAutoCommit;
-             return 'Cybercash error, invnum #' . 
-               $cust_bill->invnum. ':'. $result{'MErrMsg'};
-          } else {
-            $dbh->commit or die $dbh->errstr if $oldAutoCommit;
-            return '';
-          }
-
-        } elsif ( $processor =~ /^Business::OnlinePayment::(.*)$/ ) {
-
-          my $bop_processor = $1;
-
-          my($payname, $payfirst, $paylast);
-          if ( $self->payname ) {
-            $payname = $self->payname;
-            $payname =~ /^\s*([\w \,\.\-\']*\w)?\s+([\w\,\.\-\']+)$/
-              or do {
-                      $dbh->rollback if $oldAutoCommit;
-                      return "Illegal payname $payname";
-                    };
-            ($payfirst, $paylast) = ($1, $2);
-          } else {
-            $payfirst = $self->getfield('first');
-            $paylast = $self->getfield('first');
-            $payname =  "$payfirst $paylast";
-          }
-
-          my @invoicing_list = grep { $_ ne 'POST' } $self->invoicing_list;
-          if ( $conf->exists('emailinvoiceauto')
-               || ( $conf->exists('emailinvoiceonly') && ! @invoicing_list ) ) {
-            push @invoicing_list, $self->default_invoicing_list;
-          }
-          my $email = $invoicing_list[0];
-
-          my( $action1, $action2 ) = split(/\s*\,\s*/, $bop_action );
-        
-          my $transaction =
-            new Business::OnlinePayment( $bop_processor, @bop_options );
-          $transaction->content(
-            'type'           => 'CC',
-            'login'          => $bop_login,
-            'password'       => $bop_password,
-            'action'         => $action1,
-            'description'    => 'Internet Services',
-            'amount'         => $amount,
-            'invoice_number' => $cust_bill->invnum,
-            'customer_id'    => $self->custnum,
-            'last_name'      => $paylast,
-            'first_name'     => $payfirst,
-            'name'           => $payname,
-            'address'        => $address,
-            'city'           => $self->city,
-            'state'          => $self->state,
-            'zip'            => $self->zip,
-            'country'        => $self->country,
-            'card_number'    => $self->payinfo,
-            'expiration'     => $exp,
-            'referer'        => 'http://cleanwhisker.420.am/',
-            'email'          => $email,
-          );
-          $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    => 'Internet Services',
-            );
-
-            $capture->submit();
-
-            unless ( $capture->is_success ) {
-              my $e = "Authorization sucessful but capture failed, invnum #".
-                      $cust_bill->invnum. ': '.  $capture->result_code.
-                      ": ". $capture->error_message;
-              warn $e;
-              return $e;
-            }
-
-          }
-
-          if ( $transaction->is_success() ) {
-
-            my $cust_pay = new FS::cust_pay ( {
-               'invnum'   => $cust_bill->invnum,
-               'paid'     => $amount,
-               '_date'     => '',
-               'payby'    => 'CARD',
-               'payinfo'  => $self->payinfo,
-               'paybatch' => "$processor:". $transaction->authorization,
-            } );
-            my $error = $cust_pay->insert;
-            if ( $error ) {
-              # gah, even with transactions.
-              $dbh->commit if $oldAutoCommit; #well.
-              my $e = 'WARNING: Card debited but database not updated - '.
-                      'error applying payment, invnum #' . $cust_bill->invnum.
-                      " ($processor): $error";
-              warn $e;
-              return $e;
-            }
-          } elsif ( $options{'report_badcard'} ) {
-            $dbh->commit if $oldAutoCommit;
-            return "$processor error, invnum #". $cust_bill->invnum. ': '.
-                   $transaction->result_code. ": ". $transaction->error_message;
-          } else {
-            $dbh->commit or die $dbh->errstr if $oldAutoCommit;
-            #return '';
-          }
-
-        } else {
-          $dbh->rollback if $oldAutoCommit;
-          return "Unknown real-time processor $processor\n";
+        #add cust_bill_event
+        my $cust_bill_event = new FS::cust_bill_event {
+          'invnum'    => $cust_bill->invnum,
+          'eventpart' => $part_bill_event->eventpart,
+          '_date'     => $invoice_time,
+        };
+        $cust_bill_event->insert;
+        if ( $error ) {
+          #$dbh->rollback if $oldAutoCommit;
+          #return "error: $error";
+
+          # gah, even with transactions.
+          $dbh->commit if $oldAutoCommit; #well.
+          my $e = 'WARNING: Event run but database not updated - '.
+                  'error inserting cust_bill_event, invnum #'. $cust_bill->invnum.
+                  ', eventpart '. $part_bill_event->eventpart.
+                  ": $error";
+          warn $e;
+          return $e;
         }
 
-      } else { #batch card
-
-       my $cust_pay_batch = new FS::cust_pay_batch ( {
-         'invnum'   => $cust_bill->getfield('invnum'),
-         'custnum'  => $self->getfield('custnum'),
-         'last'     => $self->getfield('last'),
-         'first'    => $self->getfield('first'),
-         'address1' => $self->getfield('address1'),
-         'address2' => $self->getfield('address2'),
-         'city'     => $self->getfield('city'),
-         'state'    => $self->getfield('state'),
-         'zip'      => $self->getfield('zip'),
-         'country'  => $self->getfield('country'),
-         'trancode' => 77,
-         'cardnum'  => $self->getfield('payinfo'),
-         'exp'      => $self->getfield('paydate'),
-         'payname'  => $self->getfield('payname'),
-         'amount'   => $amount,
-       } );
-       my $error = $cust_pay_batch->insert;
-       if ( $error ) {
-         $dbh->rollback if $oldAutoCommit;
-         return "Error adding to cust_pay_batch: $error";
-       }
-
       }
 
-    } else {
-      $dbh->rollback if $oldAutoCommit;
-      return "Unknown payment type ". $self->payby;
     }
 
   }
+
   $dbh->commit or die $dbh->errstr if $oldAutoCommit;
   '';
 
@@ -1991,10 +1714,6 @@ sub append_fuzzyfiles {
   1;
 }
 
-=head1 VERSION
-
-$Id: cust_main.pm,v 1.55 2002-01-29 16:33:15 ivan Exp $
-
 =head1 BUGS
 
 The delete method.
@@ -2005,8 +1724,6 @@ instead of a scalar customer number.
 Bill and collect options should probably be passed as references instead of a
 list.
 
-CyberCash v2 forces us to define some variables in package main.
-
 There should probably be a configuration file with a list of allowed credit
 card types.
 
@@ -2015,9 +1732,8 @@ No multiple currency support (probably a larger project than just this module).
 =head1 SEE ALSO
 
 L<FS::Record>, L<FS::cust_pkg>, L<FS::cust_bill>, L<FS::cust_credit>
-L<FS::cust_pay_batch>, L<FS::agent>, L<FS::part_referral>,
-L<FS::cust_main_county>, L<FS::cust_main_invoice>,
-L<FS::UID>, schema.html from the base documentation.
+L<FS::agent>, L<FS::part_referral>, L<FS::cust_main_county>,
+L<FS::cust_main_invoice>, L<FS::UID>, schema.html from the base documentation.
 
 =cut
 
index 564dcca..e719645 100644 (file)
@@ -118,7 +118,6 @@ PerlSetVar Debug 2
 </pre></font>
     </ul></td>
     <td><ul>
-      <li>NOTE: Mason support is still a bit buggy in the 1.4.0 prereleases.  This will be fixed before 1.4.0.  You have been warned.
       <li>Run <tt>make masondocs</tt>
       <li>Copy <tt>masondocs/</tt> to your web server's document space.
       <li>Copy <tt>htetc/handler.pl</tt> to your web server's configuration directory.
index c4d023a..360fba6 100644 (file)
@@ -6,6 +6,7 @@
 <ul>
   <li>If migrating from less than 1.3.1, see these <a href="upgrade7.html">instructions</a> first.
   <li><font size="+2" color="#ff0000">Backup your database and current Freeside installation.</font> (with&nbsp;<a href="http://www.ca.postgresql.org/devel-corner/docs/postgres/backup.html">PostgreSQL</a>) (with&nbsp;<a href="http://www.mysql.com/documentation/mysql/bychapter/manual_MySQL_Database_Administration.html#Backup">MySQL</a>)
+  <li><a href="http://perl.apache.org/">mod_perl</a> is now required.
   <li>Install <a href="http://www.apache-asp.org/">Apache::ASP</a> or <a href="http://www.masonhq.com/">HTML::Mason</a>.
 </ul>
 <table>
@@ -33,7 +34,6 @@ PerlSetVar Global /usr/local/etc/freeside/asp-global/
 </pre></font>
     </ul></td>
     <td><ul>
-      <li>NOTE: Mason support is still a bit buggy in the 1.4.0 prereleases.  This will be fixed before 1.4.0.  You have been warned.
       <li>Run <tt>make masondocs</tt>
       <li>Copy <tt>masondocs/</tt> to your web server's document space.
       <li>Copy <tt>htetc/handler.pl</tt> to your web server's configuration directory.
index c41cfe9..70e953c 100755 (executable)
@@ -1,4 +1,4 @@
-<!-- $Id: part_bill_event.cgi,v 1.3 2002-01-30 18:22:54 ivan Exp $ -->
+<!-- $Id: part_bill_event.cgi,v 1.4 2002-02-04 16:44:47 ivan Exp $ -->
 
 <%
 
@@ -93,32 +93,56 @@ tie my %events, 'Tie::IxHash',
 
   'addpost' => {
     'name' => 'Add postal invoicing',
-    'code' => '$cust_main->invoicing_list_addpost();',
+    'code' => '$cust_main->invoicing_list_addpost(); '';',
     'pad'  => 20,
   },
 
+  'comp' => {
+    'name' => 'Pay invoice with a complimentary "payment"',
+    'code' => '$cust_bill->comp();',
+    'weight' => 30,
+  },
+
+  'realtime-card' => {
+    'name' => 'Run card with a <a href="http://search.cpan.org/search?mode=module&query=Business%3A%3AOnlinePayment">Business::OnlinePayment</a> realtime gateway',
+    'code' => '$cust_bill->realtime_card();',
+    'weight' => 30,
+  },
+
+  'realtime-card-cybercash' => {
+    'name' => '(<b>deprecated</b>) Run card with <a href="http://www.cybercash.com/cashregister">CyberCash CashRegister</a> realtime gateway',
+    'code' => '$cust_bill->realtime_card_cybercash();',
+    'weight => 30,
+  },
+
+  'batch-card' => {
+    'name' => 'Add card to the pending credit card batch',
+    'code' => '$cust_bill->batch_card();',
+    'weight' => 40,
+  },
+
   'send' => {
     'name' => 'Send invoice (email/print)',
-    'code' => '',
-    'weight' => 30
+    'code' => '$cust_bill->send();',
+    'weight' => 50,
   },
 
   'bill' => {
-    'name' => 'Generate invoices',
+    'name' => 'Generate invoices (normally only used with a <i>Late Fee</i> event)',
     'code' => '$cust_main->bill();',
-    'weight'  => 40,
+    'weight'  => 60,
   },
 
   'apply' => {
     'name' => 'Apply unapplied payments and credits',
-    'code' => '$cust_main->apply_payments; $cust_main->apply_credits;',
-    'weight'  => 50,
+    'code' => '$cust_main->apply_payments; $cust_main->apply_credits; '';',
+    'weight'  => 70,
   },
 
   'collect' => {
-    'name' => 'Collect on invoices',
+    'name' => 'Collect on invoices (normally only used with a <i>Late Fee</i> and <i>Generate Invoice</i> events)',
     'code' => '$cust_main->collect();',
-    'weight'  => 60,
+    'weight'  => 80,
   },
 
 ;
index ef6d566..6bc1568 100755 (executable)
@@ -1,4 +1,4 @@
-<!-- $Id: cust_bill.cgi,v 1.6 2002-01-30 14:18:09 ivan Exp $ -->
+<!-- $Id: cust_bill.cgi,v 1.7 2002-02-04 16:44:47 ivan Exp $ -->
 <%
 
 #untaint invnum
@@ -10,7 +10,7 @@ my $cust_bill = qsearchs('cust_bill',{'invnum'=>$invnum});
 die "Invoice #$invnum not found!" unless $cust_bill;
 my $custnum = $cust_bill->getfield('custnum');
 
-my $printed = $cust_bill->printed;
+#my $printed = $cust_bill->printed;
 
 print header('Invoice View', menubar(
   "Main Menu" => $p,
@@ -20,11 +20,10 @@ print header('Invoice View', menubar(
 print qq!<A HREF="${p}edit/cust_pay.cgi?$invnum">Enter payments (check/cash) against this invoice</A> | !
   if $cust_bill->owed > 0;
 
-print <<END;
-      <A HREF="${p}misc/print-invoice.cgi?$invnum">Reprint this invoice</A>
-      <BR><BR>(Printed $printed times)
-    <PRE>
-END
+print qq!<A HREF="${p}misc/print-invoice.cgi?$invnum">Reprint this invoice</A>!.
+#     "<BR><BR>(Printed $printed times)".
+#print cust_bill_events
+      '<PRE>'.
 
 print $cust_bill->print_text;