X-Git-Url: http://git.freeside.biz/gitweb/?a=blobdiff_plain;ds=sidebyside;f=FS%2FFS%2Fcust_bill.pm;h=8a37ada236f1692badb7ba84aa7251411eaa4141;hb=bb3aa2d253507fb15fc24c6126bee167167cb2ad;hp=5e041ea5926eed542ce109520b551c5b79f8abc9;hpb=e1cfff0375b46aaf2b5fef7fb2f9e62d7567f41f;p=freeside.git diff --git a/FS/FS/cust_bill.pm b/FS/FS/cust_bill.pm index 5e041ea59..8a37ada23 100644 --- a/FS/FS/cust_bill.pm +++ b/FS/FS/cust_bill.pm @@ -3,10 +3,12 @@ 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( $cybercash ); use vars qw( $xaction $E_NoErr ); use vars qw( $bop_processor $bop_login $bop_password $bop_action @bop_options ); +use vars qw( $ach_processor $ach_login $ach_password $ach_action @ach_options ); use vars qw( $invoice_lines @buf ); #yuck +use vars qw( $quiet ); use Date::Format; use Mail::Internet 1.44; use Mail::Header; @@ -35,6 +37,11 @@ $FS::UID::callback{'FS::cust_bill'} = sub { $invoice_from = $conf->config('invoice_from'); $smtpmachine = $conf->config('smtpmachine'); + ( $bop_processor,$bop_login, $bop_password, $bop_action ) = ( '', '', '', ''); + @bop_options = (); + ( $ach_processor,$ach_login, $ach_password, $ach_action ) = ( '', '', '', ''); + @ach_options = (); + if ( $conf->exists('cybercash3.2') ) { require CCMckLib3_2; #qw($MCKversion %Config InitConfig CCError CCDebug CCDebug2); @@ -55,7 +62,7 @@ $FS::UID::callback{'FS::cust_bill'} = sub { my($errmsg) = &CCMckErrno3_2::MCKGetErrorMessage($status); die "CCMckLib3_2::InitConfig fatal error: $errmsg\n"; } - $processor='cybercash3.2'; + $cybercash='cybercash3.2'; } elsif ( $conf->exists('business-onlinepayment') ) { ( $bop_processor, $bop_login, @@ -64,8 +71,20 @@ $FS::UID::callback{'FS::cust_bill'} = sub { @bop_options ) = $conf->config('business-onlinepayment'); $bop_action ||= 'normal authorization'; + ( $ach_processor, $ach_login, $ach_password, $ach_action, @ach_options ) = + ( $bop_processor, $bop_login, $bop_password, $bop_action, @bop_options ); + eval "use Business::OnlinePayment"; + } + + if ( $conf->exists('business-onlinepayment-ach') ) { + ( $ach_processor, + $ach_login, + $ach_password, + $ach_action, + @ach_options + ) = $conf->config('business-onlinepayment-ach'); + $ach_action ||= 'normal authorization'; eval "use Business::OnlinePayment"; - $processor="Business::OnlinePayment::$bop_processor"; } }; @@ -373,7 +392,11 @@ sub send { my @print_text = $self->print_text('', $template); my @invoicing_list = $self->cust_main->invoicing_list; - if ( grep { $_ ne 'POST' } @invoicing_list ) { #email invoice + if ( grep { $_ ne 'POST' } @invoicing_list or !@invoicing_list ) { #email + + #better to notify this person than silence + @invoicing_list = ($invoice_from) unless @invoicing_list; + #false laziness w/FS::cust_pay::delete & fs_signup_server && ::realtime_card #$ENV{SMTPHOSTS} = $smtpmachine; $ENV{MAILADDRESS} = $invoice_from; @@ -398,7 +421,7 @@ sub send { } - if ( ! @invoicing_list || grep { $_ eq 'POST' } @invoicing_list ) { #postal + if ( grep { $_ eq 'POST' } @invoicing_list ) { #postal open(LPR, "|$lpr") or return "Can't open pipe to $lpr: $!"; print LPR @print_text; @@ -443,23 +466,39 @@ first two fields (B and B) and the last five fields (B through B) 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 (only or both of B and B will be defined) -=item recur - line item recurring fee (only or both of B and B will be defined) + +=item setup - line item setup fee (one or both of B and B will be defined) + +=item recur - line item recurring fee (one or both of B and B will be defined) + =item sdate - start date for recurring fee + =item edate - end date for recurring fee =back @@ -581,32 +620,84 @@ sub comp { =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. +Attempts to pay this invoice with a credit card payment via a +Business::OnlinePayment realtime gateway. See +http://search.cpan.org/search?mode=module&query=Business%3A%3AOnlinePayment +for supported processors. =cut sub realtime_card { my $self = shift; + $self->realtime_bop( + 'CC', + $bop_processor, + $bop_login, + $bop_password, + $bop_action, + \@bop_options, + @_ + ); +} + +=item realtime_ach + +Attempts to pay this invoice with an electronic check (ACH) payment via a +Business::OnlinePayment realtime gateway. See +http://search.cpan.org/search?mode=module&query=Business%3A%3AOnlinePayment +for supported processors. + +=cut + +sub realtime_ach { + my $self = shift; + $self->realtime_bop( + 'ECHECK', + $ach_processor, + $ach_login, + $ach_password, + $ach_action, + \@ach_options, + @_ + ); +} + +=item realtime_lec + +Attempts to pay this invoice with phone bill (LEC) payment via a +Business::OnlinePayment realtime gateway. See +http://search.cpan.org/search?mode=module&query=Business%3A%3AOnlinePayment +for supported processors. + +=cut + +sub realtime_lec { + my $self = shift; + $self->realtime_bop( + 'LEC', + $bop_processor, + $bop_login, + $bop_password, + $bop_action, + \@bop_options, + @_ + ); +} + +sub realtime_bop { + my( $self, $method, $processor, $login, $password, $action, $options ) = @_; + + #trim an extraneous blank line + pop @$options if scalar(@$options) % 2 && $options->[-1] =~ /^\s*$/; + 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 ) { + if ( $cust_main->payname && $method ne 'ECHECK' ) { $payname = $cust_main->payname; $payname =~ /^\s*([\w \,\.\-\']*)?\s+([\w\,\.\-\']+)\s*$/ or do { @@ -623,11 +714,11 @@ sub realtime_card { 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]; - my( $action1, $action2 ) = split(/\s*\,\s*/, $bop_action ); + my( $action1, $action2 ) = split(/\s*\,\s*/, $action ); my $description = 'Internet Services'; if ( $conf->exists('business-onlinepayment-description') ) { @@ -644,13 +735,31 @@ sub realtime_card { $description = eval qq("$dtempl"); } + + my %content; + if ( $method eq 'CC' ) { + $content{card_number} = $cust_main->payinfo; + $cust_main->paydate =~ /^\d{2}(\d{2})[\/\-](\d+)[\/\-]\d+$/; + $content{expiration} = "$2/$1"; + } elsif ( $method eq 'ECHECK' ) { + my($account_number,$routing_code) = $cust_main->payinfo; + ( $content{account_number}, $content{routing_code} ) = + split('@', $cust_main->payinfo); + $content{bank_name} = $cust_main->payname; + $content{account_type} = 'CHECKING'; + $content{account_name} = $payname; + $content{customer_org} = $self->company ? 'B' : 'I'; + $content{customer_ssn} = $self->ss; + } elsif ( $method eq 'LEC' ) { + $content{phone} = $cust_main->payinfo; + } my $transaction = - new Business::OnlinePayment( $bop_processor, @bop_options ); + new Business::OnlinePayment( $processor, @$options ); $transaction->content( - 'type' => 'CC', - 'login' => $bop_login, - 'password' => $bop_password, + 'type' => $method, + 'login' => $login, + 'password' => $password, 'action' => $action1, 'description' => $description, 'amount' => $amount, @@ -664,34 +773,34 @@ sub realtime_card { '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, + %content, #after ); $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 ); + new Business::OnlinePayment( $processor, @$options ); my %capture = ( - type => 'CC', + %content, + type => $method, action => $action2, - login => $bop_login, - password => $bop_password, + login => $login, + password => $password, order_number => $ordernum, 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 @@ -716,18 +825,24 @@ sub realtime_card { if ( $transaction->is_success() ) { + my %method2payby = ( + 'CC' => 'CARD', + 'ECHECK' => 'CHEK', + 'LEC' => 'LECB', + ); + my $cust_pay = new FS::cust_pay ( { 'invnum' => $self->invnum, 'paid' => $amount, '_date' => '', - 'payby' => 'CARD', + 'payby' => $method2payby{$method}, '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 - '. + my $e = 'WARNING: Card/ACH debited but database not updated - '. 'error applying payment, invnum #' . $self->invnum. " ($processor): $error"; warn $e; @@ -741,7 +856,7 @@ sub realtime_card { my $perror = "$processor error, invnum #". $self->invnum. ': '. $transaction->result_code. ": ". $transaction->error_message; - if ( $conf->exists('emaildecline') + if ( !$quiet && $conf->exists('emaildecline') && grep { $_ ne 'POST' } $cust_main->invoicing_list ) { my @templ = $conf->config('declinetemplate'); @@ -762,7 +877,7 @@ sub realtime_card { "Sender: $invoice_from", "Reply-To: $invoice_from", "Date: ". time2str("%a, %d %b %Y %X %z", time), - "Subject: Your credit card could not be processed", + "Subject: Your payment could not be processed", ] ); my $message = new Mail::Internet ( 'Header' => $header, @@ -794,7 +909,7 @@ sub realtime_card_cybercash { my $amount = $self->owed; return "CyberCash CashRegister real-time card processing not enabled!" - unless $processor eq 'cybercash3.2'; + unless $cybercash eq 'cybercash3.2'; my $address = $cust_main->address1; $address .= ", ". $cust_main->address2 if $cust_main->address2; @@ -837,7 +952,7 @@ sub realtime_card_cybercash { '_date' => '', 'payby' => 'CARD', 'payinfo' => $cust_main->payinfo, - 'paybatch' => "$processor:$paybatch", + 'paybatch' => "$cybercash:$paybatch", } ); my $error = $cust_pay->insert; if ( $error ) { @@ -912,7 +1027,7 @@ sub print_text { # 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; + unless $cust_main->payname && $cust_main->payby ne 'CHEK'; my( $pr_total, @pr_cust_bill ) = $self->previous; #previous balance # my( $cr_total, @cr_cust_credit ) = $self->cust_credit; #credits @@ -1023,9 +1138,9 @@ sub print_text { 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; + foreach ( grep /invoice_lines\(\d*\)/, @invoice_template ) { #kludgy + /invoice_lines\((\d*)\)/; + $invoice_lines += $1 || scalar(@buf); $wasfunc=1; } die "no invoice_lines() functions in template?" unless $wasfunc; @@ -1038,11 +1153,12 @@ sub print_text { #setup template variables package FS::cust_bill::_template; #! - use vars qw( $invnum $date $page $total_pages @address $overdue @buf ); + use vars qw( $invnum $date $page $total_pages @address $overdue @buf $agent ); $invnum = $self->invnum; $date = $self->_date; $page = 1; + $agent = $self->cust_main->agent->agent; if ( $FS::cust_bill::invoice_lines ) { $total_pages = @@ -1083,16 +1199,14 @@ sub print_text { # ); #and subroutine for the template - sub FS::cust_bill::_template::invoice_lines { - my $lines = shift or return @buf; + my $lines = shift || scalar(@buf); map { scalar(@buf) ? shift @buf : [ '', '' ]; } ( 1 .. $lines ); } - #and fill it in $FS::cust_bill::_template::page = 1; my $lines; @@ -1112,7 +1226,7 @@ sub print_text { =head1 VERSION -$Id: cust_bill.pm,v 1.41 2002-09-05 16:51:49 ivan Exp $ +$Id: cust_bill.pm,v 1.41.2.21 2003-06-30 18:56:02 ivan Exp $ =head1 BUGS