File Coverage

blib/lib/Finance/Bank/mBank.pm
Criterion Covered Total %
statement 9 9 100.0
branch n/a
condition n/a
subroutine 3 3 100.0
pod n/a
total 12 12 100.0


line stmt bran cond sub pod time code
1             package Finance::Bank::mBank;
2              
3             our $VERSION = '0.02';
4              
5 1     1   23101 use warnings;
  1         1  
  1         29  
6 1     1   4 use strict;
  1         2  
  1         32  
7              
8 1     1   6 use base 'Class::Accessor';
  1         6  
  1         794  
9              
10             use Carp;
11             use Crypt::SSLeay;
12             use English '-no_match_vars';
13             use Web::Scraper;
14             use WWW::Mechanize;
15             use Exception::Base
16             'Exception::Login',
17             'Exception::Login::Scraping' => { isa => 'Exception::Login' },
18             'Exception::Login::Credentials' => { isa => 'Exception::Login' },
19             'Exception::HTTP' => { isa => 'Exception::Login' },
20             ;
21              
22             __PACKAGE__->mk_accessors(#{{{
23             qw/
24             userid
25             password
26             _mech
27             _is_logged_on
28             _main_content
29             _logged_userid
30             _logged_password
31             /
32             );#}}}
33              
34             =head1 NAME
35              
36             Finance::Bank::mBank - Check mBank account balance
37              
38             =head1 VERSION
39              
40             Version 0.02
41              
42             =cut
43              
44             =head1 SYNOPSIS
45              
46              
47             use Finance::Bank::mBank;
48              
49             my $mbank = Finance::Bank::mBank->new(
50             userid => 555123,
51             password => 'loremipsum'
52             );
53             # There is no need to call ->login explicitly, but it is possible
54             # $mbank->login
55             for my $account ($mbank->accounts) {
56             print "$account->{account_name}: $account->{balance}\n";
57             }
58              
59             =cut
60              
61             sub new {#{{{
62             my $class = shift;
63             my %params = (ref $_[0] eq 'HASH' ? %{ $_[0] } : @_);
64              
65             my $self = $class->SUPER::new(\%params);
66              
67             use Data::Dumper;
68             $self->_mech(
69             WWW::Mechanize->new(
70             autocheck => 1,
71             onerror => sub { Exception::HTTP->throw(message => join(q{}, @_)) },
72             )
73             );
74              
75             return $self;
76             }#}}}
77             sub login {#{{{
78             my $self = shift;
79              
80             return $self->_login(@_);
81             }#}}}
82             sub _login {#{{{
83             my $self = shift;
84              
85             $self->_check_user_change;
86              
87             return if $self->_is_logged_on;
88            
89             if (!$self->userid or !$self->password) {
90             Exception::Login::Credentials->throw( message => "No userid or password specified" );
91             }
92              
93             my $mech = $self->_mech;
94              
95             $mech->get('https://www.mbank.com.pl/');
96              
97             if (!@{$mech->forms}) {
98             Exception::Login::Scraping->throw(message => 'No forms found on login page');
99             }
100            
101             # Login form
102             my $form = $mech->form_number(1);
103             if (not $form->find_input('customer') or not $form->find_input('password')) {
104             Exception::Login::Scraping->throw( message => 'Wanted fields not found in form' );
105             }
106             $mech->field( customer => $self->userid );
107             $mech->field( password => $self->password );
108             $mech->submit;
109            
110             # Choose frame
111             $mech->follow_link( name => "MainFrame" ) or Exception::Login::Scraping->throw(message => 'No FunctionFrame was found');
112            
113             if ($mech->content =~ /Nieprawid.owy identyfikator/) {
114             Exception::Login::Credentials->throw( message => 'Invalid userid or password');
115             }
116             if ($mech->content =~ /B..d logowania/) {
117             Exception::Login->throw( message => 'Unknown login error');
118             }
119             if ($mech->content !~ /Dost.pne rachunki/) {
120             Exception::Login->throw( message => 'Unknown error')
121             }
122              
123             $self->_main_content( $mech->content );
124             $self->_logged_userid( $self->userid );
125             $self->_logged_password( $self->password );
126             $self->_is_logged_on(1);
127              
128              
129             }#}}}
130             sub accounts {#{{{
131             my $self = shift;
132              
133             $self->_login;
134              
135             return __extract_accounts( $self->_main_content );
136             }#}}}
137             sub __extract_accounts {#{{{
138             my $content = shift;
139              
140             my $account_scrap = scraper {
141             process 'p.Account', account_name => 'TEXT';
142             process 'p.Amount', balance => 'TEXT';
143             process 'p.Amount + p.Amount', available => 'TEXT';
144             };
145              
146             my $account_list_scrap = scraper {
147             process '#AccountsGrid li',
148             'accounts[]' => $account_scrap;
149             result 'accounts';
150             };
151             my $accounts = $account_list_scrap->scrape( $content );
152              
153             shift @{ $accounts }; # header row
154             pop @{ $accounts }; # summary row
155              
156             for my $account ( @{$accounts} ) {
157             $account->{balance} = __process_money_amount( $account->{balance} );
158             $account->{available} = __process_money_amount( $account->{available} );
159             }
160              
161             return @{ $accounts };
162              
163             }#}}}
164             sub _check_user_change {#{{{
165             my $self = shift;
166              
167             return if !$self->_is_logged_on;
168              
169             if ( ($self->userid ne $self->_logged_userid) or ($self->password ne $self->_logged_password) ) {
170             $self->logout;
171             }
172             }#}}}
173             sub logout {#{{{
174             my $self = shift;
175            
176             $self->_is_logged_on(0);
177             $self->_mech->get('https://www.mbank.com.pl/logout.aspx');
178             }#}}}
179             sub __process_money_amount {#{{{
180             my $val = shift;
181              
182             return undef if not defined $val;
183              
184             $val =~ s/,/./;
185             $val =~ s/\s//g;
186              
187             return $val;
188             }#}}}
189              
190             =head1 AUTHOR
191              
192             Bartek Jakubski, C<< >>
193              
194             =head1 BUGS
195              
196             Please report any bugs or feature requests to
197             C, or through the web interface at
198             L.
199             I will be notified, and then you'll automatically be notified of progress on
200             your bug as I make changes.
201              
202             =head1 SUPPORT
203              
204             You can find documentation for this module with the perldoc command.
205              
206             perldoc Finance::Bank::mBank
207              
208             You can also look for information at:
209              
210             =over 4
211              
212             =item * AnnoCPAN: Annotated CPAN documentation
213              
214             L
215              
216             =item * CPAN Ratings
217              
218             L
219              
220             =item * RT: CPAN's request tracker
221              
222             L
223              
224             =item * Search CPAN
225              
226             L
227              
228             =back
229              
230             =head1 ACKNOWLEDGEMENTS
231              
232             =head1 COPYRIGHT & LICENSE
233              
234             Copyright 2008 Bartek Jakubski, all rights reserved.
235              
236             This program is free software; you can redistribute it and/or modify it
237             under the same terms as Perl itself.
238              
239             =cut
240              
241             1; # End of Finance::Bank::mBank