fix Tokenized payinfo on upgrade if we can, RT#71513
[freeside.git] / FS / FS / cust_main.pm
index 493b1c6..62c50ad 100644 (file)
@@ -5372,19 +5372,25 @@ sub queueable_upgrade {
   eval "use FS::upgrade_journal";
   die $@ if $@;
 
-  # prior to 2013 (commit f16665c9) payinfo was stored in history if not encrypted,
-  # clear that out before encrypting/tokenizing anything else
+  # prior to 2013 (commit f16665c9) payinfo was stored in history if not
+  # encrypted, clear that out before encrypting/tokenizing anything else
   if (!FS::upgrade_journal->is_done('clear_payinfo_history')) {
-    foreach my $table ('cust_payby','cust_pay_pending','cust_pay','cust_pay_void','cust_refund') {
-      my $sql = 'UPDATE h_'.$table.' SET payinfo = NULL WHERE payinfo IS NOT NULL';
+    foreach my $table (qw(
+      cust_payby cust_pay_pending cust_pay cust_pay_void cust_refund
+    )) {
+      my $sql =
+        'UPDATE h_'.$table.' SET payinfo = NULL WHERE payinfo IS NOT NULL';
       my $sth = dbh->prepare($sql) or die dbh->errstr;
       $sth->execute or die $sth->errstr;
     }
     FS::upgrade_journal->set_done('clear_payinfo_history');
   }
 
-  # encrypt old records
-  if ($conf->exists('encryption') && !FS::upgrade_journal->is_done('encryption_check')) {
+  # fix Tokenized paycardtype and encrypt old records
+  if (    ! FS::upgrade_journal->is_done('paycardtype_Tokenized')
+       || ! FS::upgrade_journal->is_done('encryption_check')
+     )
+  {
 
     # allow replacement of closed cust_pay/cust_refund records
     local $FS::payinfo_Mixin::allow_closed_replace = 1;
@@ -5396,23 +5402,38 @@ sub queueable_upgrade {
     local $FS::UID::AutoCommit = 1;
 
     # encrypt what's there
-    foreach my $table ('cust_payby','cust_pay_pending','cust_pay','cust_pay_void','cust_refund') {
+    foreach my $table (qw(
+      cust_payby cust_pay_pending cust_pay cust_pay_void cust_refund
+    )) {
       my $tclass = 'FS::'.$table;
       my $lastrecnum = 0;
       my @recnums = ();
-      while (my $recnum = _upgrade_next_recnum(dbh,$table,\$lastrecnum,\@recnums)) {
+      while (
+        my $recnum = _upgrade_next_recnum(dbh,$table,\$lastrecnum,\@recnums)
+      ) {
         my $record = $tclass->by_key($recnum);
         next unless $record; # small chance it's been deleted, that's ok
         next unless grep { $record->payby eq $_ } @FS::Record::encrypt_payby;
         # window for possible conflict is practically nonexistant,
         #   but just in case...
         $record = $record->select_for_update;
+        if (!$record->custnum && $table eq 'cust_pay_pending') {
+          $record->set('custnum_pending',1);
+        }
+        $record->paycardtype('') if $record->paycardtype eq 'Tokenized';
+
+        local($ignore_expired_card) = 1;
+        local($ignore_banned_card) = 1;
+        local($skip_fuzzyfiles) = 1;
+        local($import) = 1;#prevent automatic geocoding (need its own variable?)
+
         my $error = $record->replace;
-        die $error if $error;
+        die "Error replacing $table ".$record->get($record->primary_key).": $error" if $error;
       }
     }
 
-    FS::upgrade_journal->set_done('encryption_check');
+    FS::upgrade_journal->set_done('paycardtype_Tokenized');
+    FS::upgrade_journal->set_done('encryption_check') if $conf->exists('encryption');
   }
 
   # now that everything's encrypted, tokenize...
@@ -5430,6 +5451,8 @@ sub _upgrade_next_recnum {
   my $sql = 'SELECT '.$tclass->primary_key.
             ' FROM '.$table.
             ' WHERE '.$tclass->primary_key.' > '.$$lastrecnum.
+            "   AND payby IN ( 'CARD', 'DCRD', 'CHEK', 'DCHK' ) ".
+            "   AND ( length(payinfo) > 80 OR paycardtype = 'Tokenized' ) ".
             ' ORDER BY '.$tclass->primary_key.' LIMIT 500';;
   my $sth = $dbh->prepare($sql) or die $dbh->errstr;
   $sth->execute() or die $sth->errstr;