File Coverage

blib/lib/Finance/Bank/Barclays.pm
Criterion Covered Total %
statement 18 89 20.2
branch 0 36 0.0
condition n/a
subroutine 6 8 75.0
pod 0 1 0.0
total 24 134 17.9


line stmt bran cond sub pod time code
1             package Finance::Bank::Barclays;
2 1     1   7717 use strict;
  1         3  
  1         46  
3 1     1   9 use warnings;
  1         2  
  1         40  
4 1     1   7 use Carp;
  1         8  
  1         100  
5             our $VERSION='0.12';
6 1     1   14243 use LWP::UserAgent;
  1         89985  
  1         40  
7 1     1   1438 use WWW::Mechanize;
  1         181123  
  1         961  
8              
9             # hackery for https proxy support
10             my $https_proxy=$ENV{https_proxy};
11             delete $ENV{https_proxy} if($https_proxy);
12              
13             our $agent = WWW::Mechanize->new(env_proxy=>1);
14              
15             $agent->env_proxy; # Load proxy settings (but not the https proxy)
16             $ENV{https_proxy}=$https_proxy if($https_proxy);
17              
18             sub check_balance {
19 0     0 0   my ($class,%opts)=@_;
20 0 0         croak "Must provide a membership number" unless exists $opts{memnumber};
21 0 0         croak "Must provide a passcode" unless exists $opts{passcode};
22 0 0         croak "Must provide a surname" unless exists $opts{surname};
23 0 0         croak "Must provide a password/memorable word" unless exists $opts{password};
24              
25 0           my $self=bless { %opts }, $class;
26              
27 0           $agent->quiet(0);
28 0           $agent->get("https://ibank.barclays.co.uk");
29 0 0         croak "index page not found (".$agent->status().")" unless ($agent->status()==200);
30 0           while(!$agent->follow_link( url_regex => qr/LoginMember.do$/i, text_regex => qr/Log-in/i)) {
31 0 0         $agent->follow_link(url_regex => qr/Welcome.do$/i ) or croak("couldn't find login link");
32             }
33 0           $agent->form(1);
34 0           $agent->field("surname",$opts{surname});
35 0           my $mno=$opts{memnumber};
36 0 0         if($mno =~ m/^20(\d{10})$/ ) { $mno=$1; }
  0            
37 0           $agent->field("membershipNo",$mno); # ignore leading "20"
38 0           $agent->click("Next");
39             #print "first: ".$agent->status()."\n";
40              
41             # There's a redirect to a 'new version' in there right now
42 0 0         if(defined($agent->find_link(tag=>"meta",n=>0))) {
43 0           $agent->follow_link(tag=>"meta",n=>0);
44             }
45              
46 0           $agent->form(1);
47 0           $agent->field("passCode",$opts{passcode});
48              
49 0           my $content=$agent->content();
50 0           my $letter1=0; my $letter2=0;
  0            
51 0 0         if($content =~ m/letter (\d) of your memorable word.*letter (\d) of your memorable word/si) {
52 0           $letter1=$1;
53 0           $letter2=$2;
54             } else {
55 0           croak "couldn't identify which letters to use";
56             }
57 0           $agent->field("firstMDC",substr($opts{password},$letter1-1,1));
58 0           $agent->field("secondMDC",substr($opts{password},$letter2-1,1));
59 0           $agent->click("Log-in");
60              
61             # parse the "at a glance" page for account balances
62 0           my @page=split(/\n/,$agent->content);
63 0           my $line="";
64 0           my @sortcodes=();
65 0           my @acnumbers=();
66 0           my @balances=();
67 0           foreach $line (@page) {
68 0 0         if($line =~ m/\s*(\d\d-\d\d-\d\d)\s+(\d+)/) {
    0          
69 0           push @sortcodes, $1;
70 0           push @acnumbers, $2;
71             } elsif($line =~ m/\\s*(-?&\#163;[0-9,.]+)\s*\
72 0           $b=$1; $b =~ s/£//; $b =~ s/,//g;
  0            
  0            
73 0           push @balances, $b;
74             }
75             }
76              
77 0 0         croak "sortcodes and balances don't match (".($#sortcodes+1)."/".($#balances+1).")" unless ($#sortcodes == $#balances);
78              
79             # try harder to find the real data (Barclays sometimes hide it
80             # behind a front screen)
81              
82 0 0         if($#sortcodes==-1) {
83 0 0         if($agent->content() =~ m/input.*checkbox.*confirmation/is) {
84 0           $agent->field("confirmation","true"); # ack, checkbox
85             }
86 0 0         $agent->click("Next") or croak "couldn't click while hunting";
87 0           @page=split(/\n/,$agent->content);
88 0           $line="";
89 0           @sortcodes=();
90 0           @acnumbers=();
91 0           @balances=();
92 0           foreach $line (@page) {
93 0 0         if($line =~ m/\s*(\d\d-\d\d-\d\d)\s+(\d+)/) {
    0          
94 0           push @sortcodes, $1;
95 0           push @acnumbers, $2;
96             } elsif($line =~ m/\\s*(-?&\#163;[0-9,.]+)\s*\
97 0           $b=$1; $b =~ s/£//; $b =~ s/,//g;
  0            
  0            
98 0           push @balances, $b;
99             }
100             }
101              
102 0 0         croak "sortcodes and balances don't match (".($#sortcodes+1)."/".($#balances+1).")" unless ($#sortcodes == $#balances);
103              
104             }
105              
106 0           my @accounts;
107 0           for(my $i=0; $i<=$#sortcodes; $i++) {
108 0           push @accounts, (bless {
109             balance => $balances[$i],
110             sort_code => $sortcodes[$i],
111             account_no => $acnumbers[$i],
112             }, "Finance::Bank::Barclays::Account");
113             }
114 0           return @accounts;
115             }
116              
117             package Finance::Bank::Barclays::Account;
118              
119             # magic
120 1     1   16 no strict;
  1         3  
  1         91  
121 0     0     sub AUTOLOAD { my $self=shift; $AUTOLOAD =~ s/.*:://; $self->{$AUTOLOAD} }
  0            
  0            
122              
123              
124             1;
125             __END__