multiple payment options, RT#23741
authorIvan Kohler <ivan@freeside.biz>
Wed, 11 Sep 2013 09:23:37 +0000 (02:23 -0700)
committerIvan Kohler <ivan@freeside.biz>
Wed, 11 Sep 2013 09:23:37 +0000 (02:23 -0700)
FS/FS/Schema.pm
FS/FS/cust_main.pm
FS/FS/cust_payby.pm
FS/FS/payinfo_Mixin.pm

index 45c0b7a..ed37904 100644 (file)
@@ -1112,7 +1112,7 @@ sub tables_hashref {
         'currency',         'char', 'NULL',  3, '', '',
 
         #deprecated, info moved to cust_payby
-        'payby',    'char', '',     4, '', '', 
+        'payby',    'char', 'NULL',     4, '', '', 
         'payinfo',  'varchar', 'NULL', 512, '', '', 
         'paycvv',   'varchar', 'NULL', 512, '', '', 
         'paymask', 'varchar', 'NULL', $char_d, '', '', 
index 13fd405..0c50b84 100644 (file)
@@ -35,6 +35,7 @@ use Business::CreditCard 0.28;
 use Locale::Country;
 use FS::UID qw( dbh driver_name );
 use FS::Record qw( qsearchs qsearch dbdef regexp_sql );
+use FS::Cursor;
 use FS::Misc qw( generate_email send_email generate_ps do_print );
 use FS::Msgcat qw(gettext);
 use FS::CurrentUser;
@@ -77,6 +78,7 @@ use FS::contact;
 use FS::Locales;
 use FS::upgrade_journal;
 use FS::sales;
+use FS::cust_payby;
 
 # 1 is mostly method/subroutine entry and options
 # 2 traces progress of some operations
@@ -1794,12 +1796,15 @@ sub check {
   }
 
   ### start of stuff moved to cust_payby
+  # then mostly kept here to support upgrades (can remove in 5.x)
+  #  but modified to allow everything to be empty
 
-  #$self->payby =~ /^(CARD|DCRD|CHEK|DCHK|LECB|BILL|COMP|PREPAY|CASH|WEST|MCRD)$/
-  #  or return "Illegal payby: ". $self->payby;
-  #$self->payby($1);
-  FS::payby->can_payby($self->table, $self->payby)
-    or return "Illegal payby: ". $self->payby;
+  if ( $self->payby ) {
+    FS::payby->can_payby($self->table, $self->payby)
+      or return "Illegal payby: ". $self->payby;
+  } else {
+    $self->payby('');
+  }
 
   $error =    $self->ut_numbern('paystart_month')
            || $self->ut_numbern('paystart_year')
@@ -1971,7 +1976,8 @@ sub check {
   if ( $self->paydate eq '' || $self->paydate eq '-' ) {
     return "Expiration date required"
       # shouldn't payinfo_check do this?
-      unless $self->payby =~ /^(BILL|PREPAY|CHEK|DCHK|LECB|CASH|WEST|MCRD|PPAL)$/;
+      unless ! $self->payby
+            || $self->payby =~ /^(BILL|PREPAY|CHEK|DCHK|LECB|CASH|WEST|MCRD|PPAL)$/;
     $self->paydate('');
   } else {
     my( $m, $y );
@@ -1999,7 +2005,7 @@ sub check {
   ) {
     $self->payname( $self->first. " ". $self->getfield('last') );
   } else {
-    $self->payname =~ /^([\w \,\.\-\'\&]+)$/
+    $self->payname =~ /^([\w \,\.\-\'\&]*)$/
       or return gettext('illegal_name'). " payname: ". $self->payname;
     $self->payname($1);
   }
@@ -5012,6 +5018,7 @@ sub process_bill_and_collect {
 # JRNL seq scan of cust_main on paydate... index on substrings?  maybe set an
 # JRNL seq scan of cust_main on payinfo.. certainly not going toi ndex that...
 # JRNL leading/trailing spaces in first, last, company
+# JRNL migrate to cust_payby
 # - otaker upgrade?  journal and call it good?  (double check to make sure
 #    we're not still setting otaker here)
 #
@@ -5088,6 +5095,45 @@ sub _upgrade_data { #class method
 
   }
 
+  unless ( FS::upgrade_journal->is_done('cust_main__cust_payby') ) {
+
+    #we don't want to decrypt them, just stuff them as-is into cust_payby
+    local(@encrypted_fields) = ();
+
+    local($FS::cust_payby::ignore_expired_card) = 1;
+    local($FS::cust_payby::ignore_banned_card) = 1;
+
+    my @payfields = qw( payby payinfo paycvv paymask
+                        paydate paystart_month paystart_year payissue
+                        payname paystate paytype payip
+                      );
+
+    my $search = new FS::Cursor {
+      'table'     => 'cust_main',
+      'extra_sql' => " WHERE ( payby IS NOT NULL AND payby != '' ) ",
+    };
+
+    while (my $cust_main = $search->fetch) {
+
+      my $cust_payby = new FS::cust_payby {
+        'custnum' => $cust_main->custnum,
+        'weight'  => 1,
+        map { $_ => $cust_main->$_(); } @payfields
+      };
+
+      my $error = $cust_payby->insert;
+      die $error if $error;
+
+      $cust_main->setfield($_, '') foreach @payfields;
+      $DEBUG = 2;
+      $error = $cust_main->replace;
+      die $error if $error;
+
+    };
+
+    FS::upgrade_journal->set_done('cust_main__trimspaces');
+  }
+
   $class->_upgrade_otaker(%opts);
 
 }
index 7bf8c76..68c8245 100644 (file)
@@ -7,7 +7,12 @@ use FS::Record qw( qsearchs ); #qsearch;
 use FS::payby;
 use FS::cust_main;
 
-use vars qw( $conf $ignore_expired_card $ignore_banned_card  );
+use vars qw( $conf @encrypted_fields
+             $ignore_expired_card $ignore_banned_card
+           );
+
+@encrypted_fields = ('payinfo', 'paycvv');
+sub nohistory_fields { ('payinfo', 'paycvv'); }
 
 $ignore_expired_card = 0;
 $ignore_banned_card = 0;
@@ -165,45 +170,25 @@ sub check {
     $self->ut_numbern('custpaybynum')
     || $self->ut_foreign_key('custnum', 'cust_main', 'custnum')
     || $self->ut_number('weight')
-    || $self->ut_('payby')
-    || $self->ut_textn('payinfo')
-    || $self->ut_textn('paycvv')
-    || $self->ut_textn('paymask')
-    || $self->ut_textn('paydate')
+    #encrypted #|| $self->ut_textn('payinfo')
+    #encrypted #|| $self->ut_textn('paycvv')
+#    || $self->ut_textn('paymask') #XXX something
+    #later #|| $self->ut_textn('paydate')
     || $self->ut_numbern('paystart_month')
     || $self->ut_numbern('paystart_year')
-    || $self->ut_textn('payissue')
-    || $self->ut_textn('payname')
-    || $self->ut_textn('paystate')
+    || $self->ut_numbern('payissue')
+#    || $self->ut_textn('payname') #XXX something
+    || $self->ut_alphan('paystate')
     || $self->ut_textn('paytype')
-    || $self->ut_textn('payip')
+    || $self->ut_ipn('payip')
   ;
   return $error if $error;
 
-
   ### from cust_main
 
-
-  #$self->payby =~ /^(CARD|DCRD|CHEK|DCHK|LECB|BILL|COMP|PREPAY|CASH|WEST|MCRD)$/
-  #  or return "Illegal payby: ". $self->payby;
-  #$self->payby($1);
   FS::payby->can_payby($self->table, $self->payby)
     or return "Illegal payby: ". $self->payby;
 
-  $error =    $self->ut_numbern('paystart_month')
-           || $self->ut_numbern('paystart_year')
-           || $self->ut_numbern('payissue')
-           || $self->ut_textn('paytype')
-  ;
-  return $error if $error;
-
-  if ( $self->payip eq '' ) {
-    $self->payip('');
-  } else {
-    $error = $self->ut_ip('payip');
-    return $error if $error;
-  }
-
   # If it is encrypted and the private key is not availaible then we can't
   # check the credit card.
   my $check_payinfo = ! $self->is_encrypted($self->payinfo);
index 66c1e59..ef260cf 100644 (file)
@@ -76,20 +76,16 @@ Card Verification Value, "CVV2" (also known as CVC2 or CID), the 3 or 4 digit nu
 
 =cut
 
+#this prevents encrypting empty values on insert?
 sub paycvv {
   my($self,$paycvv) = @_;
-  # This is only allowed in cust_main... Even then it really shouldn't be stored...
-  if ($self->table eq 'cust_main') {
-    if ( defined($paycvv) ) {
-      $self->setfield('paycvv', $paycvv); # This is okay since we are the 'setter'
-    } else {
-      $paycvv = $self->getfield('paycvv'); # This is okay since we are the 'getter'
-      return $paycvv;
-    }
+  # This is only allowed in cust_payby (formerly cust_main)
+  #  It shouldn't be stored longer than necessary to run the first transaction
+  if ( defined($paycvv) ) {
+    $self->setfield('paycvv', $paycvv);
   } else {
-#    warn "This doesn't work for other tables besides cust_main
-    '';
-  } 
+    $self->getfield('paycvv');
+  }
 }
 
 =item paymask