File Coverage

blib/lib/Finance/Bank/Wachovia/DataObtainer/WWW.pm
Criterion Covered Total %
statement 102 173 58.9
branch 17 66 25.7
condition 0 9 0.0
subroutine 33 38 86.8
pod 0 15 0.0
total 152 301 50.5


line stmt bran cond sub pod time code
1             package Finance::Bank::Wachovia::DataObtainer::WWW;
2              
3 6     6   89179 use WWW::Mechanize;
  6         1627322  
  6         341  
4 6     6   14213 use HTTP::Cookies;
  6         58080  
  6         202  
5 6     6   5040 use Finance::Bank::Wachovia::DataObtainer::WWW::Parser;
  6         16  
  6         216  
6 6     6   2877 use Finance::Bank::Wachovia::ErrorHandler;
  6         15  
  6         164  
7 6     6   43 use strict;
  6         11  
  6         201  
8 6     6   32 use warnings;
  6         11  
  6         1301  
9              
10             my $DEBUG = 1 if "@ARGV" =~ /--www-debug/;
11             my $CONFIRM_LOGIN = 1 if "@ARGV" =~ /--www-confirm/;
12             my @attrs;
13             our @ISA = qw/Finance::Bank::Wachovia::ErrorHandler/;
14              
15             BEGIN{
16 6     6   41 @attrs = qw(
17             customer_access_number
18             user_id
19             password
20             pin
21             code_word
22             cached_content
23             mech
24             start_url
25             logged_in
26             );
27            
28 6         14 my $x = @__SUPER__::ATTRIBUTES;
29 6         18 for( @attrs ){
30 54     104   2231 eval "sub _$_ { $x }";
  104     6   10401  
  6     6   27  
  6     0   27  
  0     0   0  
  0     6   0  
  6     6   27  
  6     20   28  
  20     6   123  
  6         66  
31 54         800 $x++;
32             }
33             }
34              
35             sub new {
36 10     10 0 26954 my($class, %attrs) = @_;
37 10         66 my $self = [];
38 10         47 bless $self, $class;
39 10         39 foreach my $att ( keys %attrs ){
40 10         111 $self->$att( $attrs{$att} );
41             }
42 10         44 $self->init();
43 10         41 return $self;
44             }
45              
46             sub init {
47 6     6   40 no strict;
  6         21  
  6         637  
48 10     10 0 110 my $self = shift;
49 10 50       110 $self->start_url('https://onlineservices.wachovia.com/auth/AuthService?action=presentLogin')
50             unless $self->start_url;
51 10         24 $self->[ &{"_cached_content"} ] = {};
  10         345  
52             }
53              
54             sub AUTOLOAD {
55 6     6   36 no strict 'refs';
  6         14  
  6         5002  
56 144     144   2051 our $AUTOLOAD;
57 144         219 my $self = shift;
58 144         315 my $attr = lc $AUTOLOAD;
59 144         769 $attr =~ s/.*:://;
60 144 50       1670 return $self->Error("$attr is not a valid attribute")
61             unless grep /$attr/, @attrs;
62             # get if no args passed
63 144 100       376 return $self->[ &{"_$attr"} ] unless @_;
  114         4183  
64             # set if args passed
65 30         178 $self->[ &{"_$attr"} ] = shift;
  30         1316  
66 30         109 return $self;
67             }
68              
69             sub trash_cache {
70 0     0 0 0 my $self = shift;
71 0         0 $self->[ &{"_cached_content"} ] = {};
  0         0  
72             }
73              
74             sub get_account_numbers {
75 8     8 0 1443 my $self = shift;
76 8         71 return Finance::Bank::Wachovia::DataObtainer::WWW::Parser
77             ->get_account_numbers( $self->get_summary_content() );
78             }
79              
80             sub get_credit_account_current_balance {
81 1     1 0 5 get_account_available_balance( @_ );
82             }
83              
84             sub get_credit_account_available_credit {
85 2     2 0 567 my $self = shift;
86 2 50       10 return $self->Error( "must pass credit account number" ) unless @_;
87 2         11 return Finance::Bank::Wachovia::DataObtainer::WWW::Parser
88             ->get_credit_account_available_credit( $self->get_detail_content( @_ ) );
89             }
90              
91             sub get_credit_account_limit {
92 2     2 0 529 my $self = shift;
93 2 50       11 return $self->Error( "must pass credit account number" ) unless @_;
94 2         8 return Finance::Bank::Wachovia::DataObtainer::WWW::Parser
95             ->get_credit_account_limit( $self->get_detail_content( @_ ) );
96              
97             }
98              
99             sub get_account_available_balance {
100 8     8 0 911 my $self = shift;
101 8 50       43 return $self->Error( "must pass account number" ) unless @_;
102 8         29 return Finance::Bank::Wachovia::DataObtainer::WWW::Parser
103             ->get_account_available_balance( $self->get_summary_content(), @_ );
104             }
105              
106             sub get_account_name {
107 9     9 0 1086 my $self = shift;
108 9 50       42 return $self->Error( "must pass account number" ) unless @_;
109 9         41 return Finance::Bank::Wachovia::DataObtainer::WWW::Parser
110             ->get_account_name( $self->get_summary_content(), @_ );
111             }
112              
113             sub get_account_type {
114 4     4 0 927 my($self) = shift;
115 4 50       26 return $self->Error( "must pass account number" ) unless @_;
116 4         18 return Finance::Bank::Wachovia::DataObtainer::WWW::Parser
117             ->get_account_type( $self->get_detail_content(@_) );
118             }
119              
120             sub get_account_posted_balance {
121 1     1 0 413 my $self = shift;
122 1 50       5 return $self->Error( "must pass account number" ) unless @_;
123 1         4 return Finance::Bank::Wachovia::DataObtainer::WWW::Parser
124             ->get_account_posted_balance( $self->get_detail_content(@_) );
125             }
126              
127             sub get_account_transactions {
128 3     3 0 404 my $self = shift;
129 3 50       17 return $self->Error( "must pass account number" ) unless @_;
130 3         12 return Finance::Bank::Wachovia::DataObtainer::WWW::Parser
131             ->get_account_transactions( $self->get_detail_content(@_) );
132             }
133              
134             sub get_summary_content {
135 6     6   50 no warnings;
  6         31  
  6         2251  
136 27     27 0 183 local $^W = 0;
137 27 50       80 print STDERR "Getting Summary Content:\n" if $DEBUG;
138 27         44 my $self = shift;
139 27 50       245 if( $self->cached_content->{'summary'} ){
140 27 50       69 print STDERR "Returning cached summary:\n",
141             "============== BEGIN SUMMARY =============\n",
142             $self->cached_content->{'summary'}, "\n",
143             "=============== END SUMMARY ==============\n" if $DEBUG;
144 27         124 return $self->cached_content->{'summary'};
145             }
146 0 0       0 if( ! $self->logged_in ){
147 0 0       0 $self->login
148             or return $self->Error( $self->ErrStr );
149 0 0       0 return $self->get_summary_content()
150             or return $self->Error( $self->ErrStr );
151             }
152 0         0 my $mech = $self->mech();
153 0         0 $mech->form_number( 1 );
154 0         0 $mech->field( inputName => 'RelationshipSummary' );
155 0         0 $mech->submit();
156 0         0 $self->cached_content->{'summary'} = $mech->content();
157 0 0       0 print STDERR "Returning NOT cached summary:\n",
158             "============== BEGIN SUMMARY =============\n",
159             $self->cached_content->{'summary'}, "\n",
160             "=============== END SUMMARY ==============\n" if $DEBUG;
161 0         0 return $self->cached_content->{'summary'};
162             }
163              
164             sub get_detail_content {
165 6     6   36 no warnings;
  6         11  
  6         2490  
166 14     14 0 1161 local $^W = 0;
167 14         26 my($self, $account_number) = @_;
168 14 50       41 return $self->Error( "get_detail_content in WWW must have account_number, got: '$account_number'" )
169             unless $account_number;
170 14 50       79 if( $self->cached_content->{'details'}{$account_number} ){
171 14 50       53 print STDERR "Returning cached details:\n",
172             "============ BEGIN DETAILS ===============\n",
173             $self->cached_content->{'details'}{$account_number}, "\n",
174             "============ END DETAILS =================\n" if $DEBUG;
175 14         107 return $self->cached_content->{'details'}->{$account_number};
176             }
177 0 0         unless( $self->cached_content->{'summary'} ){
178 0           $self->get_summary_content();
179             }
180 0 0         my $stmt_type = $account_number =~ /^\d{16}$/ ? 'AccountSummary' : 'AccountDetail';
181 0           my $mech = $self->mech();
182 0           $mech->form_number( 1 );
183 0           $mech->field( RelSumAcctSel => $account_number );
184 0           $mech->field( inputName => $stmt_type );
185 0           $mech->field( RelSumStmtType => $stmt_type );
186 0           $mech->submit();
187 0           $self->cached_content->{'details'}->{$account_number} = $mech->content();
188             # return to summary page
189 0           $mech->form_number( 1 );
190 0           $mech->field( inputName => 'RelationshipSummary' );
191 0           $mech->submit();
192 0 0         print STDERR "Returning NOT cached details:\n",
193             "============ BEGIN DETAILS ===============\n",
194             $self->cached_content->{'details'}{$account_number}, "\n",
195             "============ END DETAILS =================\n" if $DEBUG;
196 0           return $self->cached_content->{'details'}->{$account_number};
197             }
198              
199             # initilizes WWW::Mech object, uses it to get to summary page
200             # summary page is cached/overwritten
201             sub login {
202 6     6   36 no warnings;
  6         13  
  6         4431  
203 0     0 0   local $^W = 0;
204 0           my $self = shift;
205 0           my %p = @_;
206            
207 0   0       my $start = $p{'start_url'} || $self->start_url();
208 0 0         print STDERR "Starting Login (1)\n" if $DEBUG;
209              
210             # now we can get to business
211 0           my $mech = WWW::Mechanize->new(
212             autocheck => 1,
213             max_redirect => 1,
214             );
215            
216             # caches the mech object
217 0           $self->mech( $mech );
218              
219 0           $mech->cookie_jar(HTTP::Cookies->new()); # have to turn on cookies manually apparently
220 0           $mech->agent_alias( 'Mac Safari' ); # don't want the bank to know we are geniuses, (using perl)
221             # but we don't want them thinking we are dumb either (using MSIE).
222             # considering changing this to Firefox (mozilla), as an exercise in pointlessness.
223              
224             # make first contact
225             # TODO: add in success checking
226 0           $mech->get( $start );
227 0 0         print STDERR "Login (2) Content:\n",
228             "============ BEGIN CONTENT ===============\n",
229             $mech->content(), "\n",
230             "============ END CONTENT =================\n" if $DEBUG;
231              
232             # the website uses javascript to set this cookie, so we have to do it manually.
233             # without this, an error is returned from the website about either javascript or cookies being turned off
234 0           $mech->cookie_jar->set_cookie( undef, 'CookiesAreEnabled', 'yes', '/', '.wachovia.com', undef, undef, 1 );
235             #$mech->max_redirect(1);
236             #$mech->requests_redirectable([]);
237 0 0         if( ! $self->user_id ){
238 0 0 0       print STDERR "Logging in via CAN method...\n" if $DEBUG || $CONFIRM_LOGIN;
239 0 0         print STDERR
240             "CAN => '", $self->customer_access_number, "'\n",
241             "PIN => '", $self->pin, "'\n",
242             "CODEWORD => '", $self->code_word, "'\n"
243             if $CONFIRM_LOGIN;
244 0           $mech->form_name( 'canAuthForm' );
245 0           $mech->field( action => 'canPinLogin' );
246 0           $mech->field( CAN => $self->customer_access_number );
247 0           $mech->field( PIN => $self->pin );
248 0           $mech->field( CODEWORD => $self->code_word );
249 0           $mech->field( systemtarget => 'gotoBanking' );
250 0           $mech->field( requestTimestamp => time() ); # the website uses javascript to set this value
251             }
252             else{
253 0 0 0       print STDERR "Logging in via USERID method...\n" if $DEBUG || $CONFIRM_LOGIN;
254 0 0         print STDERR
255             "userid => '", $self->user_id, "'\n",
256             "password => '", $self->password, "'\n",
257             if $CONFIRM_LOGIN;
258 0           $mech->form_name( 'uidAuthForm' );
259 0           $mech->field( action => 'uidLogin' );
260 0           $mech->field( userid => $self->user_id );
261 0           $mech->field( password => $self->password );
262 0           $mech->field( systemtarget => 'gotoBanking' );
263 0           $mech->field( requestTimestamp => time() ); # the website uses javascript to set this value
264             }
265 0           $mech->submit();
266 0 0         print STDERR "Login (3) Content:\n",
267             "============ BEGIN CONTENT ===============\n",
268             $mech->content(), "\n",
269             "============ END CONTENT =================\n" if $DEBUG;
270 0 0         if( $mech->content() =~ /ASV\-201/ ){
271 0           return $self->Error("Login failed, bad username/password (too many of these will lock your account)");
272             }
273              
274             # after the initial commit, there is what appears to be a bunch of redirects. While there are some, there are
275             # also some javascript onLoad submits. The following code emulates that behavior (just submits a form that
276             # has a bunch of hidden inputs )
277 0           $mech->form_number( 1 );
278 0           $mech->submit();
279 0 0         print STDERR "Login (4) Content:\n",
280             "============ BEGIN CONTENT ===============\n",
281             $mech->content(), "\n",
282             "============ END CONTENT =================\n" if $DEBUG;
283              
284             # removed due to wachovia website change on 1/22
285             # $mech->form_number( 1 );
286             # $mech->submit();
287             # print STDERR "Login (5) Content:\n",
288             # "============ BEGIN CONTENT ===============\n",
289             # $mech->content(), "\n",
290             # "============ END CONTENT =================\n" if $DEBUG;
291              
292            
293 0           $self->cached_content->{'summary'} = $mech->content();
294 0           $self->logged_in( 1 );
295 0           return $self;
296             }
297              
298 0     0     sub DESTROY {}