8 use Business::CreditCard qw(generate_last_digit);
10 if ( stat('/usr/local/etc/freeside/cardfortresstest.txt') ) {
13 plan skip_all => 'CardFortress test encryption key is not installed.';
16 #local $FS::cust_main::Billing_Realtime::DEBUG = 2;
18 ### can only run on test database (company name "Freeside Test")
19 ### will run upgrade, which uses lots of prints & warns beyond regular test output
21 my $fs = FS::Test->new( user => 'admin' );
22 my $conf = FS::Conf->new;
26 like( $conf->config('company_name'), qr/^Freeside Test/, 'using test database' ) or BAIL_OUT('');
28 # test db no longer contains cardtype overrides
33 $conf->set('business-onlinepayment' => $bopconf);
34 is( join("\n",$conf->config('business-onlinepayment')), $bopconf, "setting first default gateway" ) or BAIL_OUT('');
36 # generate a few void/refund records for upgrading
38 foreach my $cust_pay ( $fs->qsearch('cust_pay',{ payby => 'CARD' }) ) {
40 $err = $cust_pay->void('Testing');
41 $err = "Voiding: $err" if $err;
43 # from realtime_refund_bop, just the important bits
44 while ( $cust_pay->unapplied < $cust_pay->paid ) {
45 my @cust_bill_pay = $cust_pay->cust_bill_pay;
46 last unless @cust_bill_pay;
47 my $cust_bill_pay = pop @cust_bill_pay;
48 $err = $cust_bill_pay->delete;
49 $err = "Refund unapply: $err" if $err;
53 my $cust_refund = new FS::cust_refund ( {
54 'custnum' => $cust_pay->cust_main->custnum,
55 'paynum' => $cust_pay->paynum,
56 'source_paynum' => $cust_pay->paynum,
57 'refund' => $cust_pay->paid,
59 'payby' => $cust_pay->payby,
60 'payinfo' => $cust_pay->payinfo,
61 'reason' => 'Testing',
62 'gatewaynum' => $cust_pay->gatewaynum,
63 'processor' => $cust_pay->payment_gateway ? $cust_pay->payment_gateway->processor : '',
64 'auth' => $cust_pay->auth,
65 'order_number' => $cust_pay->order_number,
67 $err = $cust_refund->insert( reason_type => 'Refund' );
68 $err = "Refunding: $err" if $err;
72 last unless $counter > 0;
74 ok( !$err, "create some refunds and voids" ) or BAIL_OUT($err);
76 # also, just to test behavior in this case, create a record for an aborted
77 # verification payment. this will have no customer number.
79 my $pending_failed = FS::cust_pay_pending->new({
80 'custnum_pending' => 1,
82 '_date' => time - 86400,
85 'statustext' => 'Tokenization upgrade test',
87 $err = $pending_failed->insert;
88 ok( !$err, "create a failed payment attempt" ) or BAIL_OUT($err);
90 # create two customers with an AmEx card & paycvv,
91 # then run a payment with one, just to generate some test AmEx data
95 my $cust_main = $fs->new_customer("AmEx $i");
96 isa_ok ( $cust_main, 'FS::cust_main', "AmEx $i customer" ) or BAIL_OUT('');
97 $err = $cust_main->insert;
98 ok( !$err, "insert AmEx $i customer" ) or BAIL_OUT($err);
101 my %card = random_card();
102 $card{'payinfo'} = '347594362484937';
103 $card{'paycvv'} = '1234';
104 $err = $cust_main->save_cust_payby(
106 payment_payby => $card{'payby'},
108 saved_cust_payby => \$cust_payby
110 ok( !$err, "save AmEx $i card" ) or BAIL_OUT($err);
111 $amex_cust = $cust_main;
113 $err = $amex_cust->realtime_cust_payby( amount => '1.00' );
114 ok( !$err, "run AmEx payment" ) or BAIL_OUT($err);
116 # find two stored credit cards.
117 my @cust = map { FS::cust_main->by_key($_) } (10, 12);
118 my @payby = map { ($_->cust_payby)[0] } @cust;
121 ok( $payby[0]->payby eq 'CARD' && !$payby[0]->tokenized,
122 "first customer has a non-tokenized card"
125 $err = $cust[0]->realtime_cust_payby(amount => '2.00');
126 ok( !$err, "create a payment through IPPay" )
128 $payment[0] = $fs->qsearchs('cust_pay', { custnum => $cust[0]->custnum,
130 or BAIL_OUT("can't find payment record");
132 $err = system('freeside-upgrade','admin');
133 ok( !$err, 'initial upgrade' ) or BAIL_OUT('Error string: '.$!);
135 # switch to CardFortress
148 /usr/local/etc/freeside/cardfortresstest.txt';
149 $conf->set('business-onlinepayment' => $bopconf);
150 is( join("\n",$conf->config('business-onlinepayment')), $bopconf, "setting tokenizable default gateway" ) or BAIL_OUT('');
152 # create a payment using a non-tokenized card. this should immediately
153 # trigger tokenization.
154 ok( $payby[1]->payby eq 'CARD' && ! $payby[1]->tokenized,
155 "second customer has a non-tokenized card"
158 $err = $cust[1]->realtime_cust_payby(amount => '3.00');
159 ok( !$err, "tokenize a card when it's first used for payment" )
161 $payment[1] = $fs->qsearchs('cust_pay', { custnum => $cust[1]->custnum,
163 or BAIL_OUT("can't find payment record");
164 ok( $payment[1]->tokenized, "payment is tokenized" );
165 $payby[1] = $payby[1]->replace_old;
166 ok( $payby[1]->tokenized, "card is now tokenized" );
168 # invoke the part of freeside-upgrade that tokenizes
169 FS::cust_main->queueable_upgrade();
170 #$err = system('freeside-upgrade','admin');
171 #ok( !$err, 'tokenizable upgrade' ) or BAIL_OUT('Error string: '.$!);
173 $payby[0] = $payby[0]->replace_old;
174 ok( $payby[0]->tokenized, "old card was tokenized during upgrade" );
175 $payment[0] = $payment[0]->replace_old;
176 ok( $payment[0]->tokenized, "old payment was tokenized during upgrade" );
177 ok( ($payment[0]->cust_pay_pending)[0]->tokenized, "old cust_pay_pending was tokenized during upgrade" );
179 $pending_failed = $pending_failed->replace_old;
180 ok( $pending_failed->tokenized, "cust_pay_pending with no customer was tokenized" );
182 # add a new payment card to one customer
183 $payby[2] = FS::cust_payby->new({
184 custnum => $cust[0]->custnum,
187 $err = $payby[2]->insert;
188 ok( !$err, "new card was saved" );
189 ok($payby[2]->tokenized, "new card is tokenized" );
192 my $payinfo = '4111' . join('', map { int(rand(10)) } 1 .. 11);
193 $payinfo .= generate_last_digit($payinfo);
194 my $paydate = DateTime->now
196 ->truncate(to => 'month')
198 return ( 'payby' => 'CARD',
199 'payinfo' => $payinfo,
200 'paydate' => $paydate,
201 'payname' => 'Tokenize Me',