rework card tokenization test
authorMark Wells <mark@freeside.biz>
Mon, 5 Dec 2016 07:13:04 +0000 (23:13 -0800)
committerMark Wells <mark@freeside.biz>
Mon, 5 Dec 2016 07:25:35 +0000 (23:25 -0800)
FS/t/suite/13-tokenization.t

index 9a3ef3f..b4d204f 100755 (executable)
@@ -1,36 +1,29 @@
 #!/usr/bin/perl
 
+use strict;
 use FS::Test;
-use Test::More tests => 9;
+use Test::More;
 use FS::Conf;
+use FS::cust_main;
+use Business::CreditCard qw(generate_last_digit);
+use DateTime;
+if ( stat('/usr/local/etc/freeside/cardfortresstest.txt') ) {
+  plan tests => 18;
+} else {
+  plan skip_all => 'CardFortress test encryption key is not installed.';
+}
 
 ### can only run on test database (company name "Freeside Test")
 ### will run upgrade, which uses lots of prints & warns beyond regular test output
 
 my $fs = FS::Test->new( user => 'admin' );
-my $conf = new_ok('FS::Conf');
+my $conf = FS::Conf->new;
 my $err;
 my $bopconf;
 
 like( $conf->config('company_name'), qr/^Freeside Test/, 'using test database' ) or BAIL_OUT('');
 
-# some pre-upgrade cleanup, upgrade will fail if these are still configured
-foreach my $cust_main ( $fs->qsearch('cust_main') ) {
-  my @count = $fs->qsearch('agent_payment_gateway', { agentnum => $cust_main->agentnum } );
-  if (@count > 1) {
-    note("DELETING CARDTYPE GATEWAYS");
-    foreach my $apg (@count) {
-      $err = $apg->delete if $apg->cardtype;
-      last if $err;
-    }
-    @count = $fs->qsearch('agent_payment_gateway', { agentnum => $cust_main->agentnum } );
-    if (@count > 1) {
-      $err = "Still found ".@count." gateways for custnum ".$cust_main->custnum;
-      last;
-    }
-  }
-}
-ok( !$err, "remove obsolete payment gateways" ) or BAIL_OUT($err);
+# test db no longer contains cardtype overrides
 
 $bopconf = 
 'IPPay
@@ -78,9 +71,40 @@ foreach my $cust_pay ( $fs->qsearch('cust_pay',{ payby => 'CARD' }) ) {
 }
 ok( !$err, "create some refunds and voids" ) or BAIL_OUT($err);
 
+# also, just to test behavior in this case, create a record for an aborted
+# verification payment. this will have no customer number.
+
+my $pending_failed = FS::cust_pay_pending->new({
+  'custnum_pending' => 1,
+  'paid'    => '1.00',
+  '_date'   => time - 86400,
+  random_card(),
+  'status'  => 'failed',
+  'statustext' => 'Tokenization upgrade test',
+});
+$err = $pending_failed->insert;
+ok( !$err, "create a failed payment attempt" ) or BAIL_OUT($err);
+
+# find two stored credit cards.
+my @cust = map { FS::cust_main->by_key($_) } (10, 12);
+my @payby = map { ($_->cust_payby)[0] } @cust;
+my @payment;
+
+ok( $payby[0]->payby eq 'CARD' && !$payby[0]->tokenized,
+  "first customer has a non-tokenized card"
+  ) or BAIL_OUT();
+
+$err = $cust[0]->realtime_cust_payby(amount => '2.00');
+ok( !$err, "create a payment through IPPay" )
+  or BAIL_OUT($err);
+$payment[0] = $fs->qsearchs('cust_pay', { custnum => $cust[0]->custnum,
+                                     paid => '2.00' })
+  or BAIL_OUT("can't find payment record");
+
 $err = system('freeside-upgrade','admin');
 ok( !$err, 'initial upgrade' ) or BAIL_OUT('Error string: '.$!);
 
+# switch to CardFortress
 $bopconf =
 'CardFortress
 cardfortresstest
@@ -97,26 +121,78 @@ private_key
 $conf->set('business-onlinepayment' => $bopconf);
 is( join("\n",$conf->config('business-onlinepayment')), $bopconf, "setting tokenizable default gateway" ) or BAIL_OUT('');
 
-foreach my $pg ($fs->qsearch('payment_gateway')) {
-  unless ($pg->gateway_module eq 'CardFortress') {
-    note('UPGRADING NON-CF PAYMENT GATEWAY');
-    my %pgopts = (
-      gateway          => $pg->gateway_module,
-      gateway_login    => $pg->gateway_username,
-      gateway_password => $pg->gateway_password,
-      private_key      => '/usr/local/etc/freeside/cardfortresstest.txt',
-    );
-    $pg->gateway_module('CardFortress');
-    $pg->gateway_username('cardfortresstest');
-    $pg->gateway_password('(TEST54)');
-    $err = $pg->replace(\%pgopts);
-    last if $err;
-  }
+# create a payment using a non-tokenized card. this should immediately
+# trigger tokenization.
+ok( $payby[1]->payby eq 'CARD' && ! $payby[1]->tokenized,
+  "second customer has a non-tokenized card"
+  ) or BAIL_OUT();
+
+$err = $cust[1]->realtime_cust_payby(amount => '3.00');
+ok( !$err, "tokenize a card when it's first used for payment" )
+  or BAIL_OUT($err);
+$payment[1] = $fs->qsearchs('cust_pay', { custnum => $cust[1]->custnum,
+                                     paid => '3.00' })
+  or BAIL_OUT("can't find payment record");
+ok( $payment[1]->tokenized, "payment is tokenized" );
+$payby[1] = $payby[1]->replace_old;
+ok( $payby[1]->tokenized, "card is now tokenized" );
+
+# test db doesn't have this
+#foreach my $pg ($fs->qsearch('payment_gateway')) {
+#  unless ($pg->gateway_module eq 'CardFortress') {
+#    note('UPGRADING NON-CF PAYMENT GATEWAY');
+#    my %pgopts = (
+#      gateway          => $pg->gateway_module,
+#      gateway_login    => $pg->gateway_username,
+#      gateway_password => $pg->gateway_password,
+#      private_key      => '/usr/local/etc/freeside/cardfortresstest.txt',
+#    );
+#    $pg->gateway_module('CardFortress');
+#    $pg->gateway_username('cardfortresstest');
+#    $pg->gateway_password('(TEST54)');
+#    $err = $pg->replace(\%pgopts);
+#    last if $err;
+#  }
+#}
+#ok( !$err, "remove non-CF payment gateways" ) or BAIL_OUT($err);
+
+# invoke the part of freeside-upgrade that tokenizes
+FS::cust_main->queueable_upgrade( quiet => 1 );
+#$err = system('freeside-upgrade','admin');
+#ok( !$err, 'tokenizable upgrade' ) or BAIL_OUT('Error string: '.$!);
+
+$payby[0] = $payby[0]->replace_old;
+ok( $payby[0]->tokenized, "old card was tokenized during upgrade" );
+$payment[0] = $payment[0]->replace_old;
+ok( $payment[0]->tokenized, "old payment was tokenized during upgrade" );
+ok( ($payment[0]->cust_pay_pending)[0]->tokenized, "old cust_pay_pending was tokenized during upgrade" );
+
+$pending_failed = $pending_failed->replace_old;
+ok( $pending_failed->tokenized, "cust_pay_pending with no customer was tokenized" );
+
+# add a new payment card to one customer
+$payby[2] = FS::cust_payby->new({
+  custnum => $cust[0]->custnum,
+  random_card(),
+});
+$err = $payby[2]->insert;
+ok( !$err, "new card was saved" );
+ok($payby[2]->tokenized, "new card is tokenized" );
+
+sub random_card {
+  my $payinfo = '4111' . join('', map { int(rand(10)) } 1 .. 11);
+  $payinfo .= generate_last_digit($payinfo);
+  my $paydate = DateTime->now
+                ->add('years' => 1)
+                ->truncate(to => 'month')
+                ->strftime('%F');
+  return ( 'payby'    => 'CARD',
+           'payinfo'  => $payinfo,
+           'paydate'  => $paydate,
+           'payname'  => 'Tokenize Me',
+  );
 }
-ok( !$err, "remove non-CF payment gateways" ) or BAIL_OUT($err);
 
-$err = system('freeside-upgrade','admin');
-ok( !$err, 'tokenizable upgrade' ) or BAIL_OUT('Error string: '.$!);
 
 1;