[freeside-commits] branch master updated. 9a8399783bb9d87ef662b4371bebe983d2781dce

Jonathan Prykop jonathan at 420.am
Sat Dec 3 09:20:53 PST 2016


The branch, master has been updated
       via  9a8399783bb9d87ef662b4371bebe983d2781dce (commit)
      from  0ed150d5dd7027513942b74eb362460bc7c2e884 (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 9a8399783bb9d87ef662b4371bebe983d2781dce
Author: Jonathan Prykop <jonathan at freeside.biz>
Date:   Sat Dec 3 10:36:03 2016 -0600

    71513: Card tokenization [refund gateway choice]

diff --git a/FS/FS/cust_main/Billing_Realtime.pm b/FS/FS/cust_main/Billing_Realtime.pm
index f331a39..3a3947b 100644
--- a/FS/FS/cust_main/Billing_Realtime.pm
+++ b/FS/FS/cust_main/Billing_Realtime.pm
@@ -1480,10 +1480,12 @@ sub realtime_refund_bop {
       @bop_options = $payment_gateway->gatewaynum
                        ? $payment_gateway->options
                        : @{ $payment_gateway->get('options') };
+      my %bop_options = @bop_options;
 
       return "processor of payment $options{'paynum'} $processor does not".
              " match default processor $conf_processor"
-        unless $processor eq $conf_processor;
+        unless ($processor eq $conf_processor)
+            || (($conf_processor eq 'CardFortress') && ($processor eq $bop_options{'gateway'}));
 
     }
 
@@ -1492,9 +1494,7 @@ sub realtime_refund_bop {
            # like a normal transaction 
  
     my $payment_gateway =
-      $self->agent->payment_gateway( 'method'  => $options{method},
-                                     #'payinfo' => $payinfo,
-                                   );
+      $self->agent->payment_gateway( 'method'  => $options{method} );
     my( $processor, $login, $password, $namespace ) =
       map { my $method = "gateway_$_"; $payment_gateway->$method }
         qw( module username password namespace );
@@ -1627,18 +1627,22 @@ sub realtime_refund_bop {
     if length($payip);
 
   my $payinfo = '';
+  my $paymask = ''; # for refund record
   if ( $options{method} eq 'CC' ) {
 
     if ( $cust_pay ) {
       $content{card_number} = $payinfo = $cust_pay->payinfo;
+      $paymask = $cust_pay->paymask;
       (exists($options{'paydate'}) ? $options{'paydate'} : $cust_pay->paydate)
         =~ /^\d{2}(\d{2})[\/\-](\d+)[\/\-]\d+$/ &&
         ($content{expiration} = "$2/$1");  # where available
     } else {
-      $content{card_number} = $payinfo = $self->payinfo;
-      (exists($options{'paydate'}) ? $options{'paydate'} : $self->paydate)
-        =~ /^\d{2}(\d{2})[\/\-](\d+)[\/\-]\d+$/;
-      $content{expiration} = "$2/$1";
+      # this really needs a better cleanup
+      die "Refund without paynum not supported";
+#      $content{card_number} = $payinfo = $self->payinfo;
+#      (exists($options{'paydate'}) ? $options{'paydate'} : $self->paydate)
+#        =~ /^\d{2}(\d{2})[\/\-](\d+)[\/\-]\d+$/;
+#      $content{expiration} = "$2/$1";
     }
 
   } elsif ( $options{method} eq 'ECHECK' ) {
@@ -1702,6 +1706,7 @@ sub realtime_refund_bop {
     '_date'    => '',
     'payby'    => $bop_method2payby{$options{method}},
     'payinfo'  => $payinfo,
+    'paymask'  => $paymask,
     'reasonnum'     => $options{'reasonnum'},
     'gatewaynum'    => $gatewaynum, # may be null
     'processor'     => $processor,
@@ -2443,7 +2448,7 @@ CUSTLOOP:
       }
 
       # only load gateway if we need to, and only need to load it once
-      my $payment_gateway ||= $cust_main->_payment_gateway({
+      $payment_gateway ||= $cust_main->_payment_gateway({
         'method'  => 'CC',
         'conf'    => $conf,
         'nofatal' => 1, # handle lack of gateway smoothly below
@@ -2543,15 +2548,72 @@ CUSTLOOP:
         $dbh->commit or die $dbh->errstr; # commit log message
       }
 
-      # don't use customer agent gateway here, use the gatewaynum specified by the record
-      my $gateway = FS::payment_gateway->by_key_or_default( 
-        'method'     => 'CC',
-        'conf'       => $conf,
-        'nofatal'    => 1,
-        'gatewaynum' => $record->gatewaynum || '',
-      );
+      my $cust_main = $record->cust_main;
+      if (!$cust_main) {
+        # might happen for cust_pay_pending from failed verify records,
+        #   in which case we attempt tokenization without cust_main
+        # everything else should absolutely have a cust_main
+        unless ($table eq 'cust_pay_pending' && $record->{'custnum_pending'}) {
+          my $error = "Could not load cust_main for $table ".$record->get($record->primary_key);
+          if ($opt{'queue'}) {
+            $log->critical($error);
+            $dbh->commit or die $dbh->errstr; # commit log message
+            next;
+          }
+          $dbh->rollback if $oldAutoCommit;
+          die $error;
+        }
+      }
+
+      my $gateway;
+
+      # use the gatewaynum specified by the record if possible
+      $gateway = FS::payment_gateway->by_key_with_namespace(
+        'gatewaynum' => $record->gatewaynum,
+      ) if $record->gateway;
+
+      # otherwise use the cust agent gateway if possible (which realtime_refund_bop would do)
+      # otherwise just use default gateway
+      unless ($gateway) {
+
+        $gateway = $cust_main 
+                 ? $cust_main->agent->payment_gateway
+                 : FS::payment_gateway->default_gateway;
+
+        # check for processor mismatch
+        unless ($table eq 'cust_pay_pending') { # has no processor table
+          if (my $processor = $record->processor) {
+
+            my $conf_processor = $gateway->gateway_module;
+            my %bop_options = $gateway->gatewaynum
+                            ? $gateway->options
+                            : @{ $gateway->get('options') };
+
+            # this is the same standard used by realtime_refund_bop
+            unless (
+              ($processor eq $conf_processor) ||
+              (($conf_processor eq 'CardFortress') && ($processor eq $bop_options{'gateway'}))
+            ) {
+
+              # processors don't match, so refund already cannot be run on this object,
+              # regardless of what we do now...
+              # but unless we gotta tokenize everything, just leave well enough alone
+              unless ($require_tokenized) {
+                warn "Skipping mismatched processor for $table ".$record->get($record->primary_key) if $debug;
+                next;
+              }
+              ### no error--we'll tokenize using the new gateway, just to remove stored payinfo,
+              ### because refunds are already impossible for this record, anyway
+
+            } # end processor mismatch
+
+          } # end record has processor
+        } # end not cust_pay_pending
+
+      }
+
+      # means no default gateway, no promise to tokenize, can skip
       unless ($gateway) {
-        # means no default gateway, no promise to tokenize, can skip
         warn "Skipping missing gateway for $table ".$record->get($record->primary_key) if $debug;
         next;
       }
@@ -2570,24 +2632,7 @@ CUSTLOOP:
         next;
       }
 
-      my $cust_main = $record->cust_main;
-      if (!$cust_main) {
-        # might happen for cust_pay_pending from failed verify records,
-        #   in which case we attempt tokenization without cust_main
-        # everything else should absolutely have a cust_main
-        if ($table eq 'cust_pay_pending' && $record->{'custnum_pending'}) {
-          warn "ATTEMPTING GATEWAY-ONLY TOKENIZE" if $debug;
-        } else {
-          my $error = "Could not load cust_main for $table ".$record->get($record->primary_key);
-          if ($opt{'queue'}) {
-            $log->critical($error);
-            $dbh->commit or die $dbh->errstr; # commit log message
-            next;
-          }
-          $dbh->rollback if $oldAutoCommit;
-          die $error;
-        }
-      }
+      warn "ATTEMPTING GATEWAY-ONLY TOKENIZE" if $debug && !$cust_main;
 
       # if we got this far, time to mutex
       $record = $record->select_for_update;
diff --git a/FS/FS/payinfo_Mixin.pm b/FS/FS/payinfo_Mixin.pm
index be37568..3a51022 100644
--- a/FS/FS/payinfo_Mixin.pm
+++ b/FS/FS/payinfo_Mixin.pm
@@ -195,8 +195,6 @@ sub payinfo_check {
   FS::payby->can_payby($self->table, $self->payby)
     or return "Illegal payby: ". $self->payby;
 
-  my $conf = new FS::Conf;
-
   if ( $self->payby eq 'CARD' && ! $self->is_encrypted($self->payinfo) ) {
 
     my $payinfo = $self->payinfo;
diff --git a/FS/FS/payinfo_transaction_Mixin.pm b/FS/FS/payinfo_transaction_Mixin.pm
index c27d049..1b5a0cd 100644
--- a/FS/FS/payinfo_transaction_Mixin.pm
+++ b/FS/FS/payinfo_transaction_Mixin.pm
@@ -102,8 +102,6 @@ auth, and order_number) as well as payby and payinfo
 sub payinfo_check {
   my $self = shift;
 
-  my $conf = new FS::Conf;
-
   $self->SUPER::payinfo_check()
   || $self->ut_numbern('gatewaynum')
   # not ut_foreign_keyn, it causes upgrades to fail
diff --git a/FS/FS/payment_gateway.pm b/FS/FS/payment_gateway.pm
index 170d37a..3500bf9 100644
--- a/FS/FS/payment_gateway.pm
+++ b/FS/FS/payment_gateway.pm
@@ -385,6 +385,23 @@ sub default_gateway {
   return $payment_gateway;
 }
 
+=item by_key_with_namespace GATEWAYNUM
+
+Like usual by_key, but makes sure namespace is set,
+and dies if not found.
+
+=cut
+
+sub by_key_with_namespace {
+  my $self = shift;
+  my $payment_gateway = $self->by_key(@_);
+  die "payment_gateway not found"
+    unless $payment_gateway;
+  $payment_gateway->gateway_namespace('Business::OnlinePayment')
+    unless $payment_gateway->gateway_namespace;
+  return $payment_gateway;
+}
+
 =item by_key_or_default OPTIONS
 
 Either returns the gateway specified by option gatewaynum, or the default gateway.
@@ -399,13 +416,7 @@ sub by_key_or_default {
   my ($self,%options) = @_;
 
   if ($options{'gatewaynum'}) {
-    my $payment_gateway = $self->by_key($options{'gatewaynum'});
-    # regardless of nofatal, which is only meant for handling lack of default gateway
-    die "payment_gateway ".$options{'gatewaynum'}." not found"
-      unless $payment_gateway;
-    $payment_gateway->gateway_namespace('Business::OnlinePayment')
-      unless $payment_gateway->gateway_namespace;
-    return $payment_gateway;
+    return $self->by_key_with_namespace($options{'gatewaynum'});
   } else {
     return $self->default_gateway(%options);
   }

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

Summary of changes:
 FS/FS/cust_main/Billing_Realtime.pm |  115 ++++++++++++++++++++++++-----------
 FS/FS/payinfo_Mixin.pm              |    2 -
 FS/FS/payinfo_transaction_Mixin.pm  |    2 -
 FS/FS/payment_gateway.pm            |   25 +++++---
 4 files changed, 98 insertions(+), 46 deletions(-)




More information about the freeside-commits mailing list