From: ivan Date: Mon, 4 Feb 2002 16:44:48 +0000 (+0000) Subject: billing events! X-Git-Tag: freeside_1_4_0pre11~112 X-Git-Url: http://git.freeside.biz/gitweb/?p=freeside.git;a=commitdiff_plain;h=8cbba53b09bb5b09355316b7ff8948500c3b4b76 billing events! --- diff --git a/FS/FS/cust_bill.pm b/FS/FS/cust_bill.pm index 8b326a56f..00135afa1 100644 --- a/FS/FS/cust_bill.pm +++ b/FS/FS/cust_bill.pm @@ -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 and L for conversion functions. =item charged - amount of this invoice -=item printed - how many times this invoice has been printed automatically -(see L). +=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) 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. + +=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). + +=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 diff --git a/FS/FS/cust_main.pm b/FS/FS/cust_main.pm index 8a7a6f806..62f61a689 100644 --- a/FS/FS/cust_main.pm +++ b/FS/FS/cust_main.pm @@ -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? You can't delete a customer with invoices (see L), -or credits (see L) or payments (see L). +or credits (see L), payments (see L) or +refunds (see L). =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). 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 +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). Also see L and L for conversion functions. -batch_card - Set this true to batch cards (see L). 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, L, L, L -L, L, L, -L, L, -L, schema.html from the base documentation. +L, L, L, +L, L, schema.html from the base documentation. =cut diff --git a/httemplate/docs/install.html b/httemplate/docs/install.html index 564dccaba..e719645a4 100644 --- a/httemplate/docs/install.html +++ b/httemplate/docs/install.html @@ -118,7 +118,6 @@ PerlSetVar Debug 2
    -
  • 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.
  • Run make masondocs
  • Copy masondocs/ to your web server's document space.
  • Copy htetc/handler.pl to your web server's configuration directory. diff --git a/httemplate/docs/upgrade8.html b/httemplate/docs/upgrade8.html index c4d023a58..360fba691 100644 --- a/httemplate/docs/upgrade8.html +++ b/httemplate/docs/upgrade8.html @@ -6,6 +6,7 @@ @@ -33,7 +34,6 @@ PerlSetVar Global /usr/local/etc/freeside/asp-global/
      -
    • 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.
    • Run make masondocs
    • Copy masondocs/ to your web server's document space.
    • Copy htetc/handler.pl to your web server's configuration directory. diff --git a/httemplate/edit/part_bill_event.cgi b/httemplate/edit/part_bill_event.cgi index c41cfe9cf..70e953ca0 100755 --- a/httemplate/edit/part_bill_event.cgi +++ b/httemplate/edit/part_bill_event.cgi @@ -1,4 +1,4 @@ - + <% @@ -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 Business::OnlinePayment realtime gateway', + 'code' => '$cust_bill->realtime_card();', + 'weight' => 30, + }, + + 'realtime-card-cybercash' => { + 'name' => '(deprecated) Run card with CyberCash CashRegister 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 Late Fee 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 Late Fee and Generate Invoice events)', 'code' => '$cust_main->collect();', - 'weight' => 60, + 'weight' => 80, }, ; diff --git a/httemplate/view/cust_bill.cgi b/httemplate/view/cust_bill.cgi index ef6d56611..6bc156816 100755 --- a/httemplate/view/cust_bill.cgi +++ b/httemplate/view/cust_bill.cgi @@ -1,4 +1,4 @@ - + <% #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!Enter payments (check/cash) against this invoice | ! if $cust_bill->owed > 0; -print <Reprint this invoice -

      (Printed $printed times) -
      -END
      +print qq!Reprint this invoice!.
      +#     "

      (Printed $printed times)". +#print cust_bill_events + '
      '.
       
       print $cust_bill->print_text;