use Carp;
use Data::Dumper;
use Business::CreditCard 0.35;
+use Business::OnlinePayment;
use FS::UID qw( dbh myconnect );
use FS::Record qw( qsearch qsearchs );
use FS::payby;
$options{amount} = $self->balance unless exists( $options{amount} );
return '' unless $options{amount} > 0;
+ #huh, in v4, realtime_bop no longer will just process a card without passing
+ # payinfo or cust_payby...
+ if ( ! $options{'payinfo'} && ! $options{'cust_payby'} && $self->has_cust_payby_auto ) {
+ my @cust_payby = $self->cust_payby;
+ $options{'cust_payby'} = $cust_payby[0];
+ }
+
return $self->realtime_bop({%options});
}
# set fields from passed cust_payby
_bop_cust_payby_options(\%options);
+ # check for banned credit card/ACH
+ my $ban = FS::banned_pay->ban_search(
+ 'payby' => $bop_method2payby{$options{method}},
+ 'payinfo' => $options{payinfo},
+ );
+ return "Banned credit card" if $ban && $ban->bantype ne 'warn';
+
# possibly run a separate transaction to tokenize card number,
# so that we never store tokenized card info in cust_pay_pending
if (($options{method} eq 'CC') && !$self->tokenized($options{'payinfo'})) {
eval "use $namespace";
die $@ if $@;
- ###
- # check for banned credit card/ACH
- ###
-
- my $ban = FS::banned_pay->ban_search(
- 'payby' => $bop_method2payby{$options{method}},
- 'payinfo' => $options{payinfo},
- );
- return "Banned credit card" if $ban && $ban->bantype ne 'warn';
-
###
# check for term discount validity
###
$content{'name'} = $self->get('first'). ' '. $self->get('last');
}
}
- if ( $cust_pay->payby eq 'CARD'
- && !$content{'card_number'}
- && $cust_pay->tokenized
- ) {
- $content{'card_token'} = $cust_pay->payinfo;
- }
$void->content( 'action' => 'void', %content );
$void->test_transaction(1)
if $conf->exists('business-onlinepayment-test_transaction');
return "No cust_payby" unless $options{'cust_payby'};
_bop_cust_payby_options(\%options);
+ # check for banned credit card/ACH
+ my $ban = FS::banned_pay->ban_search(
+ 'payby' => $bop_method2payby{'CC'},
+ 'payinfo' => $options{payinfo},
+ );
+ return "Banned credit card" if $ban && $ban->bantype ne 'warn';
+
# possibly run a separate transaction to tokenize card number,
# so that we never store tokenized card info in cust_pay_pending
if (($options{method} eq 'CC') && !$self->tokenized($options{'payinfo'})) {
eval "use $namespace";
die $@ if $@;
- ###
- # check for banned credit card/ACH
- ###
-
- my $ban = FS::banned_pay->ban_search(
- 'payby' => $bop_method2payby{'CC'},
- 'payinfo' => $options{payinfo},
- );
- return "Banned credit card" if $ban && $ban->bantype ne 'warn';
-
###
# massage data
###
return '' unless $options{method} eq 'CC';
return '' if $self->tokenized($options{payinfo}); #already tokenized
+ # check for banned credit card/ACH
+ my $ban = FS::banned_pay->ban_search(
+ 'payby' => $bop_method2payby{'CC'},
+ 'payinfo' => $options{payinfo},
+ );
+ return "Banned credit card" if $ban && $ban->bantype ne 'warn';
+
###
# select a gateway
###
return '' unless $supported_actions{'CC'}
&& grep /^Tokenize$/, @{$supported_actions{'CC'}};
- ###
- # check for banned credit card/ACH
- ###
-
- my $ban = FS::banned_pay->ban_search(
- 'payby' => $bop_method2payby{'CC'},
- 'payinfo' => $options{payinfo},
- );
- return "Banned credit card" if $ban && $ban->bantype ne 'warn';
-
###
# massage data
###
and any other tokenizable records will still be committed.
If the I<daily> flag is also set, detection of existing untokenized records will
-record a critical error in the system log (because they should have never appeared
+record an info message in the system log (because they should have never appeared
in the first place.) Tokenization will still be attempted.
If any configured gateways do NOT have the ability to tokenize, or if a
#acts on all customers
my %opt = @_;
my $debug = !$opt{'quiet'} || $DEBUG;
+ my $hascritical = 0;
warn "token_check called with opts\n".Dumper(\%opt) if $debug;
my $cache = {}; #cache for module info
- # look for a gateway that can't tokenize
+ # look for a gateway that can and can't tokenize
my $require_tokenized = 1;
+ my $someone_tokenizing = 0;
foreach my $gateway (
FS::payment_gateway->all_gateways(
'method' => 'CC',
# no default gateway, no promise to tokenize
# can just load other gateways as-needeed below
$require_tokenized = 0;
- last;
+ last if $someone_tokenizing;
+ next;
}
my $info = _token_check_gateway_info($cache,$gateway);
die $info unless ref($info); # means it's an error message
- unless ($info->{'can_tokenize'}) {
+ if ($info->{'can_tokenize'}) {
+ $someone_tokenizing = 1;
+ } else {
# a configured gateway can't tokenize, that's all we need to know right now
# can just load other gateways as-needeed below
$require_tokenized = 0;
- last;
+ last if $someone_tokenizing;
}
}
+ unless ($someone_tokenizing) { #no need to check, if no one can tokenize
+ warn "no gateways tokenize\n" if $debug;
+ return;
+ }
+
warn "REQUIRE TOKENIZED" if $require_tokenized && $debug;
# upgrade does not call this with autocommit turned on,
}
if ($require_tokenized && $opt{'daily'}) {
- $log->critical("Untokenized card number detected in cust_payby ".$cust_payby->custpaybynum);
+ $log->info("Untokenized card number detected in cust_payby ".$cust_payby->custpaybynum. '; tokenizing');
$dbh->commit or die $dbh->errstr; # commit log message
}
}
my $error = "No gateway found for custnum ".$cust_main->custnum;
if ($opt{'queue'}) {
+ $hascritical = 1;
$log->critical($error);
$dbh->commit or die $dbh->errstr; # commit error message
next; # not next CUSTLOOP, want to record error for every cust_payby
if ($error) {
$error = "Error tokenizing cust_payby ".$cust_payby->custpaybynum.": ".$error;
if ($opt{'queue'}) {
+ $hascritical = 1;
$log->critical($error);
$dbh->commit or die $dbh->errstr; # commit log message, release mutex
next; # not next CUSTLOOP, want to record error for every cust_payby
while (my $recnum = _token_check_next_recnum($dbh,$table,$step,\$offset,\@recnums)) {
my $record = $tclass->by_key($recnum);
+ unless ($record->payby eq 'CARD') {
+ warn "Skipping non-card record for $table ".$record->get($record->primary_key) if $debug;
+ next;
+ }
if (FS::cust_main::Billing_Realtime->tokenized($record->payinfo)) {
warn "Skipping tokenized record for $table ".$record->get($record->primary_key) if $debug;
next;
}
if ($require_tokenized && $opt{'daily'}) {
- $log->critical("Untokenized card number detected in $table ".$record->get($record->primary_key));
+ $log->info("Untokenized card number detected in $table ".$record->get($record->primary_key). ';tokenizing');
$dbh->commit or die $dbh->errstr; # commit log message
}
} else {
my $error = "Could not load cust_main for $table ".$record->get($record->primary_key);
if ($opt{'queue'}) {
+ $hascritical = 1;
$log->critical($error);
$dbh->commit or die $dbh->errstr; # commit log message
next;
if ($error) {
$error = "Error tokenizing $table ".$record->get($record->primary_key).": ".$error;
if ($opt{'queue'}) {
+ $hascritical = 1;
$log->critical($error);
$dbh->commit or die $dbh->errstr; # commit log message, release mutex
next;
$dbh->commit or die $dbh->errstr if $oldAutoCommit;
- return '';
+ return $hascritical ? 'Critical errors occurred on some records, see system log' : '';
}
# not a method!
my $recnum = shift @$recnums;
return $recnum if $recnum;
my $tclass = 'FS::'.$table;
- my $sth = $dbh->prepare('SELECT '.$tclass->primary_key.' FROM '.$table.' ORDER BY '.$tclass->primary_key.' LIMIT '.$step.' OFFSET '.$$offset) or die $dbh->errstr;
+ my $sth = $dbh->prepare(
+ 'SELECT '.$tclass->primary_key.
+ ' FROM '.$table.
+ " WHERE ( is_tokenized IS NULL OR is_tokenized = '' ) ".
+ ' ORDER BY '.$tclass->primary_key.
+ ' LIMIT '.$step.
+ ' OFFSET '.$$offset
+ ) or die $dbh->errstr;
$sth->execute() or die $sth->errstr;
my @recnums;
while (my $rec = $sth->fetchrow_hashref) {