[freeside-commits] branch master updated. b72e70605eb51f2336230bbef8bf7f6fd2fe6456

Jonathan Prykop jonathan at 420.am
Sat Oct 29 10:03:31 PDT 2016


The branch, master has been updated
       via  b72e70605eb51f2336230bbef8bf7f6fd2fe6456 (commit)
      from  0d9ffbafedc170c79ef5587af8c836579eb1c6fc (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
commit b72e70605eb51f2336230bbef8bf7f6fd2fe6456
Author: Jonathan Prykop <jonathan at freeside.biz>
Date:   Sat Oct 29 12:02:31 2016 -0500

    71513: Card tokenization [checkpoint, not ready for backport]

diff --git a/FS/FS/ClientAPI/MyAccount.pm b/FS/FS/ClientAPI/MyAccount.pm
index 7c17ae3..091d6ac 100644
--- a/FS/FS/ClientAPI/MyAccount.pm
+++ b/FS/FS/ClientAPI/MyAccount.pm
@@ -1022,7 +1022,7 @@ sub validate_payment {
     validate($payinfo)
       or return { 'error' => gettext('invalid_card') }; # . ": ". $self->payinfo
     return { 'error' => gettext('unknown_card_type') }
-      if $payinfo !~ /^99\d{14}$/ && cardtype($payinfo) eq "Unknown";
+      if !$cust_main->tokenized($payinfo) && cardtype($payinfo) eq "Unknown";
 
     if ( length($p->{'paycvv'}) && $p->{'paycvv'} !~ /^\s*$/ ) {
       if ( cardtype($payinfo) eq 'American Express card' ) {
diff --git a/FS/FS/cust_main.pm b/FS/FS/cust_main.pm
index 9c8e374..2136ad2 100644
--- a/FS/FS/cust_main.pm
+++ b/FS/FS/cust_main.pm
@@ -1895,7 +1895,7 @@ sub check_payinfo_cardtype {
   my $payinfo = $self->payinfo;
   $payinfo =~ s/\D//g;
 
-  return '' if $payinfo =~ /^99\d{14}$/; #token
+  return '' if $self->tokenized($payinfo); #token
 
   my %bop_card_types = map { $_=>1 } values %{ card_types() };
   my $cardtype = cardtype($payinfo);
diff --git a/FS/FS/cust_main/Billing_Realtime.pm b/FS/FS/cust_main/Billing_Realtime.pm
index 81b00aa..09e2dfa 100644
--- a/FS/FS/cust_main/Billing_Realtime.pm
+++ b/FS/FS/cust_main/Billing_Realtime.pm
@@ -376,14 +376,18 @@ sub _bop_content {
 }
 
 sub _tokenize_card {
-  my ($self,$transaction,$cust_payby,$log,%opt) = @_;
+  my ($self,$transaction,$options,$log,%opt) = @_;
+  # options is for entire process, so we can update payinfo
+  # opt is just for this call, only key is replace
 
+  my $cust_payby = $options->{'cust_payby'};
   if ( $cust_payby
        and $transaction->can('card_token') 
        and $transaction->card_token 
-       and $cust_payby->payinfo !~ /^99\d{14}$/ #not already tokenized
+       and !$cust_payby->tokenized #not already tokenized
   ) {
 
+    $options->{'payinfo'} = $transaction->card_token;
     $cust_payby->payinfo($transaction->card_token);
 
     my $error;
@@ -400,6 +404,18 @@ sub _tokenize_card {
 
 }
 
+# only store payinfo in cust_pay/cust_pay_pending
+# if it's a tokenized card or if processor requires card for void
+sub _cust_pay_opts {
+  my ($self,$payby,$payinfo,$transaction) = @_;
+  ( (($payby eq 'CARD') && $self->tokenized($payinfo))
+    || (($payby eq 'CARD') && $transaction->info('CC_void_requires_card'))
+    || (($payby eq 'CHEK') && $transaction->info('ECHECK_void_requires_account'))
+  )
+    ? ('payinfo' => $payinfo)
+    : ();
+}
+
 my %bop_method2payby = (
   'CC'     => 'CARD',
   'ECHECK' => 'CHEK',
@@ -665,12 +681,15 @@ sub realtime_bop {
 
   #okay, good to go, if we're a duplicate, cust_pay_pending will kick us out
 
+  my $transaction = new $namespace( $payment_gateway->gateway_module,
+                                    $self->_bop_options(\%options),
+                                  );
+
   my $cust_pay_pending = new FS::cust_pay_pending {
     'custnum'           => $self->custnum,
     'paid'              => $options{amount},
     '_date'             => '',
     'payby'             => $bop_method2payby{$options{method}},
-    'payinfo'           => $options{payinfo},
     'paymask'           => $options{paymask},
     'paydate'           => $paydate,
     'recurring_billing' => $content{recurring_billing},
@@ -679,6 +698,7 @@ sub realtime_bop {
     'gatewaynum'        => $payment_gateway->gatewaynum || '',
     'session_id'        => $options{session_id} || '',
     'jobnum'            => $options{depend_jobnum} || '',
+    $self->_cust_pay_opts($options{payinfo},$transaction),
   };
   $cust_pay_pending->payunique( $options{payunique} )
     if defined($options{payunique}) && length($options{payunique});
@@ -695,10 +715,6 @@ sub realtime_bop {
   my( $action1, $action2 ) =
     split( /\s*\,\s*/, $payment_gateway->gateway_action );
 
-  my $transaction = new $namespace( $payment_gateway->gateway_module,
-                                    $self->_bop_options(\%options),
-                                  );
-
   $transaction->content(
     'type'           => $options{method},
     $self->_bop_auth(\%options),          
@@ -811,7 +827,7 @@ sub realtime_bop {
   # Tokenize
   ###
 
-  my $error = $self->_tokenize_card($transaction,$options{'cust_payby'},$log,'replace' => 1);
+  my $error = $self->_tokenize_card($transaction,\%options,$log,'replace' => 1);
   return $error if $error;
 
   ###
@@ -849,9 +865,7 @@ sub fake_bop {
      'paid'     => $options{amount},
      '_date'    => '',
      'payby'    => $bop_method2payby{$options{method}},
-     #'payinfo'  => $payinfo,
      'payinfo'  => '4111111111111111',
-     #'paydate'  => $paydate,
      'paydate'  => '2012-05-01',
      'processor'      => 'FakeProcessor',
      'auth'           => '54',
@@ -925,7 +939,6 @@ sub _realtime_bop_result {
        'paid'     => $cust_pay_pending->paid,
        '_date'    => '',
        'payby'    => $cust_pay_pending->payby,
-       'payinfo'  => $options{'payinfo'},
        'paymask'  => $options{'paymask'} || $cust_pay_pending->paymask,
        'paydate'  => $cust_pay_pending->paydate,
        'pkgnum'   => $cust_pay_pending->pkgnum,
@@ -935,6 +948,7 @@ sub _realtime_bop_result {
        'auth'           => $transaction->authorization,
        'order_number'   => $order_number || '',
        'no_auto_apply'  => $options{'no_auto_apply'} ? 'Y' : '',
+       $self->_cust_pay_opts($options{payinfo},$transaction),
     } );
     #doesn't hurt to know, even though the dup check is in cust_pay_pending now
     $cust_pay->payunique( $options{payunique} )
@@ -1840,7 +1854,9 @@ sub realtime_verify_bop {
   ###
 
   my $error;
-  my $transaction; #need this back so we can do _tokenize_card
+  my $transaction = new $namespace( $payment_gateway->gateway_module,
+                                    $self->_bop_options(\%options),
+                                  ); #need this back so we can do _tokenize_card
 
   # don't mutex the customer here, because they might be uncommitted. and
   # this is only verification. it doesn't matter if they have other
@@ -1851,13 +1867,13 @@ sub realtime_verify_bop {
     'paid'              => '1.00',
     '_date'             => '',
     'payby'             => $bop_method2payby{'CC'},
-    'payinfo'           => $options{payinfo},
     'paymask'           => $options{paymask},
     'paydate'           => $paydate,
     'pkgnum'            => $options{'pkgnum'},
     'status'            => 'new',
     'gatewaynum'        => $payment_gateway->gatewaynum || '',
     'session_id'        => $options{session_id} || '',
+    $self->_cust_pay_opts($options{payinfo},$transaction),
   };
   $cust_pay_pending->payunique( $options{payunique} )
     if defined($options{payunique}) && length($options{payunique});
@@ -1888,10 +1904,6 @@ sub realtime_verify_bop {
       if $DEBUG > 1;
     warn Dumper($cust_pay_pending) if $DEBUG > 2;
 
-    $transaction = new $namespace( $payment_gateway->gateway_module,
-                                   $self->_bop_options(\%options),
-                                    );
-
     $transaction->content(
       'type'           => 'CC',
       $self->_bop_auth(\%options),          
@@ -2115,7 +2127,7 @@ sub realtime_verify_bop {
 
   #important that we not pass replace option here,
   #because cust_payby->replace uses realtime_verify_bop!
-  $self->_tokenize_card($transaction,$options{'cust_payby'},$log);
+  $self->_tokenize_card($transaction,\%options,$log);
 
   ###
   # result handling
@@ -2162,7 +2174,7 @@ sub realtime_tokenize {
   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
@@ -2253,7 +2265,7 @@ sub realtime_tokenize {
 
     #important that we not pass replace option here, 
     #because cust_payby->replace uses realtime_tokenize!
-    $self->_tokenize_card($transaction,$options{'cust_payby'},$log);
+    $self->_tokenize_card($transaction,\%options,$log);
 
   } else {
 
@@ -2265,6 +2277,12 @@ sub realtime_tokenize {
 
 }
 
+sub tokenized {
+  my $this = shift;
+  my $payinfo = shift;
+  $payinfo =~ /^99\d{14}$/;
+}
+
 =back
 
 =head1 BUGS
diff --git a/FS/FS/cust_payby.pm b/FS/FS/cust_payby.pm
index 626fc9f..53608cf 100644
--- a/FS/FS/cust_payby.pm
+++ b/FS/FS/cust_payby.pm
@@ -276,7 +276,7 @@ sub replace {
 
   if ( $self->payby =~ /^(CARD|CHEK)$/
        && ( ( $self->get('payinfo') ne $old->get('payinfo')
-              && $self->get('payinfo') !~ /^99\d{14}$/ 
+              && !$self->tokenized 
             )
             || grep { $self->get($_) ne $old->get($_) } qw(paydate payname)
           )
@@ -357,7 +357,7 @@ sub check {
       or return gettext('invalid_card'); # . ": ". $self->payinfo;
 
     my $cardtype = cardtype($payinfo);
-    $cardtype = 'Tokenized' if $self->payinfo =~ /^99\d{14}$/; #token
+    $cardtype = 'Tokenized' if $self->tokenized; #token
     
     return gettext('unknown_card_type') if $cardtype eq "Unknown";
     
@@ -546,7 +546,7 @@ sub check_payinfo_cardtype {
   my $payinfo = $self->payinfo;
   $payinfo =~ s/\D//g;
 
-  if ( $payinfo =~ /^99\d{14}$/ ) {
+  if ( $self->tokenized($payinfo) ) {
     $self->set('paycardtype', 'Tokenized');
     return '';
   }
diff --git a/FS/FS/payinfo_Mixin.pm b/FS/FS/payinfo_Mixin.pm
index 3a32ad5..a0a2cbc 100644
--- a/FS/FS/payinfo_Mixin.pm
+++ b/FS/FS/payinfo_Mixin.pm
@@ -67,9 +67,9 @@ sub payinfo {
   my($self,$payinfo) = @_;
 
   if ( defined($payinfo) ) {
-    $self->paymask($self->mask_payinfo) unless $self->payinfo =~ /^99\d{14}$/; #make sure old mask is set
+    $self->paymask($self->mask_payinfo) unless $self->tokenized; #make sure old mask is set
     $self->setfield('payinfo', $payinfo);
-    $self->paymask($self->mask_payinfo) unless $payinfo =~ /^99\d{14}$/; #remask unless tokenizing
+    $self->paymask($self->mask_payinfo) unless $self->tokenized($payinfo); #remask unless tokenizing
   } else {
     $self->getfield('payinfo');
   }
@@ -130,7 +130,7 @@ sub mask_payinfo {
   # Check to see if it's encrypted...
   if ( ref($self) && $self->is_encrypted($payinfo) ) {
     return 'N/A';
-  } elsif ( $payinfo =~ /^99\d{14}$/ || $payinfo eq 'N/A' ) { #token
+  } elsif ( $self->tokenized($payinfo) || $payinfo eq 'N/A' ) { #token
     return 'N/A (tokenized)'; #?
   } else { # if not, mask it...
 
@@ -198,7 +198,7 @@ sub payinfo_check {
 
     my $payinfo = $self->payinfo;
     my $cardtype = cardtype($payinfo);
-    $cardtype = 'Tokenized' if $payinfo =~ /^99\d{14}$/;
+    $cardtype = 'Tokenized' if $self->tokenized;
     $self->set('paycardtype', $cardtype);
 
     if ( $ignore_masked_payinfo and $self->mask_payinfo eq $self->payinfo ) {
@@ -233,6 +233,7 @@ sub payinfo_check {
     }
   }
 
+  return '';
 }
 
 =item payby_payinfo_pretty [ LOCALE ]
@@ -453,6 +454,15 @@ sub process_set_cardtype {
   }
 }
 
+sub tokenized {
+  my $self = shift;
+  my $payinfo = scalar(@_) ? shift : $self->payinfo;
+  ## or just $self->cust_main->tokenized($payinfo) ??
+  ##   everything that currently uses this mixin is linked to cust_main,
+  ##   but just in case, false laziness w/ FS::cust_main::Billing_Realtime
+  $payinfo =~ /^99\d{14}$/;
+}
+
 =back
 
 =head1 BUGS
diff --git a/httemplate/misc/process/payment.cgi b/httemplate/misc/process/payment.cgi
index 74ca734..84687f0 100644
--- a/httemplate/misc/process/payment.cgi
+++ b/httemplate/misc/process/payment.cgi
@@ -135,7 +135,7 @@ if ( (my $custpaybynum = scalar($cgi->param('custpaybynum'))) > 0 ) {
     validate($payinfo)
       or errorpage(gettext('invalid_card'));
 
-    unless ( $payinfo =~ /^99\d{14}$/ ) { #token
+    unless ( $cust_main->tokenized($payinfo) ) { #token
 
       my $cardtype = cardtype($payinfo);
 

-----------------------------------------------------------------------

Summary of changes:
 FS/FS/ClientAPI/MyAccount.pm        |    2 +-
 FS/FS/cust_main.pm                  |    2 +-
 FS/FS/cust_main/Billing_Realtime.pm |   58 +++++++++++++++++++++++------------
 FS/FS/cust_payby.pm                 |    6 ++--
 FS/FS/payinfo_Mixin.pm              |   18 ++++++++---
 httemplate/misc/process/payment.cgi |    2 +-
 6 files changed, 58 insertions(+), 30 deletions(-)




More information about the freeside-commits mailing list