65202fdfd5cdc55243d888b8438839558806e014
[freeside.git] / FS / t / suite / 14-tokenization_refund.t
1 #!/usr/bin/perl
2
3 use strict;
4 use FS::Test;
5 use Test::More;
6 use FS::Conf;
7 use FS::cust_main;
8 use Business::CreditCard qw(generate_last_digit);
9 use DateTime;
10 if ( stat('/usr/local/etc/freeside/cardfortresstest.txt') ) {
11   plan tests => 33;
12 } else {
13   plan skip_all => 'CardFortress test encryption key is not installed.';
14 }
15
16 #local $FS::cust_main::Billing_Realtime::DEBUG = 2;
17
18 my $fs = FS::Test->new( user => 'admin' );
19 my $conf = FS::Conf->new;
20 my $err;
21 my @bopconf;
22
23 ### can only run on test database (company name "Freeside Test")
24 like( $conf->config('company_name'), qr/^Freeside Test/, 'using test database' ) or BAIL_OUT('');
25
26 ### database might need to be upgraded before this,
27 ### but doesn't matter if existing records are tokenized or not,
28 ### this is all about testing new record creation
29
30 # these will just get in the way for now
31 foreach my $apg ($fs->qsearch('agent_payment_gateway')) {
32   $err = $apg->delete;
33   last if $err;
34 }
35 ok( !$err, 'removing agent gateway overrides' ) or BAIL_OUT($err);
36
37 # will need this
38 my $reason = FS::reason->new_or_existing(
39   reason => 'Token Test',
40   type   => 'Refund',
41   class  => 'F',
42 );
43 isa_ok ( $reason, 'FS::reason', "refund reason" ) or BAIL_OUT('');
44
45 # non-tokenizing gateway
46 push @bopconf,
47 'IPPay
48 TESTTERMINAL';
49
50 # tokenizing gateway
51 push @bopconf,
52 'CardFortress
53 cardfortresstest
54 (TEST54)
55 Normal Authorization
56 gateway
57 IPPay
58 gateway_login
59 TESTTERMINAL
60 gateway_password
61
62 private_key
63 /usr/local/etc/freeside/cardfortresstest.txt';
64
65 # for attempting refund post-tokenization
66 my $n_cust_main;
67 my $n_cust_pay;
68
69 foreach my $tokenizing (0,1) {
70
71   my $adj = $tokenizing ? 'tokenizable' : 'non-tokenizable';
72
73   # set payment gateway
74   $conf->set('business-onlinepayment' => $bopconf[$tokenizing]);
75   is( join("\n",$conf->config('business-onlinepayment')), $bopconf[$tokenizing], "set $adj default gateway" ) or BAIL_OUT('');
76
77   if ($tokenizing) {
78
79     my $n_paynum = $n_cust_pay->paynum;
80
81     # refund the previous non-tokenized payment through CF
82     $err = $n_cust_main->realtime_refund_bop({
83       reasonnum => $reason->reasonnum,
84       paynum    => $n_paynum,
85       method    => 'CC',
86     });
87     ok( !$err, "run post-switch refund" ) or BAIL_OUT($err);
88
89     # check for void record
90     my $n_cust_pay_void = $fs->qsearchs('cust_pay_void',{ paynum => $n_paynum });
91     isa_ok( $n_cust_pay_void, 'FS::cust_pay_void', 'post-switch void') or BAIL_OUT("paynum $n_paynum");
92
93     # check that void tokenized
94     ok ( $n_cust_pay_void->tokenized, "post-switch void tokenized" ) or BAIL_OUT("paynum $n_paynum");
95
96     # check for no refund record
97     ok( !$fs->qsearch('cust_refund',{ source_paynum => $n_paynum }), "post-switch refund did not generate cust_refund" ) or BAIL_OUT("paynum $n_paynum");
98
99   }
100
101   # create customer
102   my $cust_main = $fs->new_customer($adj);
103   isa_ok ( $cust_main, 'FS::cust_main', "$adj customer" ) or BAIL_OUT('');
104
105   # insert customer
106   $err = $cust_main->insert;
107   ok( !$err, "insert $adj customer" ) or BAIL_OUT($err);
108
109   # add card
110   my $cust_payby;
111   my %card = random_card();
112   $err = $cust_main->save_cust_payby(
113     %card,
114     payment_payby => $card{'payby'},
115     auto => 1,
116     saved_cust_payby => \$cust_payby
117   );
118   ok( !$err, "save $adj card" ) or BAIL_OUT($err);
119
120   # retrieve card
121   isa_ok ( $cust_payby, 'FS::cust_payby', "$adj card" ) or BAIL_OUT('');
122
123   # check that card tokenized or not
124   if ($tokenizing) {
125     ok( $cust_payby->tokenized, 'new cust card tokenized' ) or BAIL_OUT('');
126   } else {
127     ok( !$cust_payby->tokenized, 'new cust card not tokenized' ) or BAIL_OUT('');
128   }
129
130   # run a payment
131   $err = $cust_main->realtime_cust_payby( amount => '1.00' );
132   ok( !$err, "run $adj payment" ) or BAIL_OUT($err);
133
134   # get the payment
135   my $cust_pay = $fs->qsearchs('cust_pay',{ custnum => $cust_main->custnum }); 
136   isa_ok ( $cust_pay, 'FS::cust_pay', "$adj payment" ) or BAIL_OUT('');
137
138   # refund the payment
139   $err = $cust_main->realtime_refund_bop({
140     reasonnum => $reason->reasonnum,
141     paynum    => $cust_pay->paynum,
142     method    => 'CC',
143   });
144   ok( !$err, "run $adj refund" ) or BAIL_OUT($err);
145
146   unless ($tokenizing) {
147
148     # run a second payment, to refund after switch
149     $err = $cust_main->realtime_cust_payby( amount => '2.00' );
150     ok( !$err, "run $adj second payment" ) or BAIL_OUT($err);
151     
152     # get the second payment
153     $n_cust_pay = $fs->qsearchs('cust_pay',{ custnum => $cust_main->custnum, paid => '2.00' });
154     isa_ok ( $n_cust_pay, 'FS::cust_pay', "$adj second payment" ) or BAIL_OUT('');
155
156     $n_cust_main = $cust_main;
157
158   }
159
160   #check that all transactions tokenized or not
161   foreach my $table (qw(cust_pay_pending cust_pay cust_pay_void)) {
162     foreach my $record ($fs->qsearch($table,{ custnum => $cust_main->custnum })) {
163       if ($tokenizing) {
164         $err = "record not tokenized: $table ".$record->get($record->primary_key)
165           unless $record->tokenized;
166       } else {
167         $err = "record tokenized: $table ".$record->get($record->primary_key)
168           if $record->tokenized;
169       }
170       last if $err;
171     }
172   }
173   ok( !$err, "$adj transaction token check" ) or BAIL_OUT($err);
174
175   #make sure we voided
176   ok( $fs->qsearch('cust_pay_void',{ custnum => $cust_main->custnum}), "$adj refund voided" ) or BAIL_OUT('');
177
178   #make sure we didn't generate refund records
179   ok( !$fs->qsearch('cust_refund',{ custnum => $cust_main->custnum}), "$adj refund did not generate cust_refund" ) or BAIL_OUT('');
180
181 };
182
183 exit;
184
185 sub random_card {
186   my $payinfo = '4111' . join('', map { int(rand(10)) } 1 .. 11);
187   $payinfo .= generate_last_digit($payinfo);
188   my $paydate = DateTime->now
189                 ->add('years' => 1)
190                 ->truncate(to => 'month')
191                 ->strftime('%F');
192   return ( 'payby'    => 'CARD',
193            'payinfo'  => $payinfo,
194            'paydate'  => $paydate,
195            'payname'  => 'Tokenize Me',
196   );
197 }
198
199 1;
200