}
sub _tokenize_card {
- my ($self,$transaction,$cust_payby,$log,%opt) = @_;
-
- if ( $cust_payby
- and $transaction->can('card_token')
+ my ($self,$transaction,$options) = @_;
+ if ( $transaction->can('card_token')
and $transaction->card_token
- and $cust_payby->payinfo !~ /^99\d{14}$/ #not already tokenized
+ and !$self->tokenized($options->{'payinfo'})
) {
-
- $cust_payby->payinfo($transaction->card_token);
-
- my $error;
- $error = $cust_payby->replace if $opt{'replace'};
- if ( $error ) {
- $log->error('Error storing token for cust '.$self->custnum.', cust_payby '.$cust_payby->custpaybynum.': '.$error);
- return $error;
- } else {
- $log->debug('Tokenized card for cust '.$self->custnum.', cust_payby '.$cust_payby->custpaybynum);
- return '';
- }
-
+ $options->{'payinfo'} = $transaction->card_token; #for creating cust_pay
+ $options->{'cust_payby'}->payinfo($transaction->card_token) if $options->{'cust_payby'};
+ return $transaction->card_token;
}
-
+ return '';
}
my %bop_method2payby = (
my $cc_surcharge = 0;
my $cc_surcharge_pct = 0;
- $cc_surcharge_pct = $conf->config('credit-card-surcharge-percentage')
- if $conf->config('credit-card-surcharge-percentage')
+ $cc_surcharge_pct = $conf->config('credit-card-surcharge-percentage', $self->agentnum)
+ if $conf->config('credit-card-surcharge-percentage', $self->agentnum)
&& $options{method} eq 'CC';
# always add cc surcharge if called from event
) {
my $error = $self->remove_cvv_from_cust_payby($options{payinfo});
if ( $error ) {
+ $log->critical('Error removing cvv for cust '.$self->custnum.': '.$error);
+ #not returning error, should at least attempt to handle results of an otherwise valid transaction
warn "WARNING: error removing cvv: $error\n";
}
}
# Tokenize
###
- my $error = $self->_tokenize_card($transaction,$options{'cust_payby'},$log,'replace' => 1);
- return $error if $error;
+ if (my $card_token = $self->_tokenize_card($transaction,\%options)) {
+ # cpp will be replaced in _realtime_bop_result
+ $cust_pay_pending->payinfo($card_token);
+ if ($options{'cust_payby'} and my $error = $options{'cust_payby'}->replace) {
+ $log->critical('Error storing token for cust '.$self->custnum.', cust_payby '.$options{'cust_payby'}->custpaybynum.': '.$error);
+ #not returning error, should at least attempt to handle results of an otherwise valid transaction
+ #this leaves real card number in cust_payby, but can't do much else if cust_payby won't replace
+ }
+ }
###
# result handling
'paid' => $options{amount},
'_date' => '',
'payby' => $bop_method2payby{$options{method}},
- #'payinfo' => $payinfo,
'payinfo' => '4111111111111111',
- #'paydate' => $paydate,
'paydate' => '2012-05-01',
'processor' => 'FakeProcessor',
'auth' => '54',
or return "no payment gateway in arguments to _realtime_bop_result";
$cust_pay_pending->status($transaction->is_success() ? 'captured' : 'declined');
- my $cpp_captured_err = $cust_pay_pending->replace;
+ my $cpp_captured_err = $cust_pay_pending->replace; #also saves tokenization
return $cpp_captured_err if $cpp_captured_err;
if ( $transaction->is_success() ) {
}
###
+ # remove paycvv here? need to find out if a reversed auth
+ # counts as an initial transaction for paycvv retention requirements
+ ###
+
+ ###
# Tokenize
###
- #important that we not pass replace option here,
+ #important that we not replace cust_payby here,
#because cust_payby->replace uses realtime_verify_bop!
- $self->_tokenize_card($transaction,$options{'cust_payby'},$log);
+ if (my $card_token = $self->_tokenize_card($transaction,\%options)) {
+ $cust_pay_pending->payinfo($card_token);
+ my $cpp_token_err = $cust_pay_pending->replace;
+ #this leaves real card number in cust_payby, but can't do much else if cust_payby won't replace
+ return $cpp_token_err if $cpp_token_err;
+ }
###
# result handling
return "No cust_payby" unless $options{'cust_payby'};
$self->_bop_cust_payby_options(\%options);
return '' unless $options{method} eq 'CC';
- return '' if $options{payinfo} =~ /^99\d{14}$/; #already tokenized
+ return '' if $self->tokenized($options{payinfo}); #already tokenized
###
# select a gateway
);
my %supported_actions = $transaction->info('supported_actions');
- return '' unless $supported_actions{'CC'} and grep(/^Tokenize$/,@{$supported_actions{'CC'}});
+ return '' unless $supported_actions{'CC'}
+ && grep /^Tokenize$/, @{$supported_actions{'CC'}};
###
# check for banned credit card/ACH
if ( $transaction->card_token() ) { # no is_success flag
- #important that we not pass replace option here,
+ # realtime_tokenize should not clear paycvv at this time. it might be
+ # needed for the first transaction, and a tokenize isn't actually a
+ # transaction that hits the gateway. at some point in the future, card
+ # fortress should take on the "store paycvv until first transaction"
+ # functionality and we should fix this in freeside, but i that's a bigger
+ # project for another time.
+
+ #important that we not replace cust_payby here,
#because cust_payby->replace uses realtime_tokenize!
- $self->_tokenize_card($transaction,$options{'cust_payby'},$log);
+ $self->_tokenize_card($transaction,\%options);
} else {
}
+
+=item tokenized PAYINFO
+
+Convenience wrapper for L<FS::payinfo_Mixin/tokenized>
+
+PAYINFO is required
+
+=cut
+
+sub tokenized {
+ my $this = shift;
+ my $payinfo = shift;
+ FS::cust_pay->tokenized($payinfo);
+}
+
=back
=head1 BUGS