File Coverage

blib/lib/Finance/Bank/PSK.pm
Criterion Covered Total %
statement 21 106 19.8
branch 0 22 0.0
condition 0 8 0.0
subroutine 7 14 50.0
pod 2 2 100.0
total 30 152 19.7


line stmt bran cond sub pod time code
1             # $Id: PSK.pm,v 1.8 2004/05/02 12:00:18 florian Exp $
2              
3             package Finance::Bank::PSK;
4              
5             require 5.005_62;
6 1     1   676 use strict;
  1         2  
  1         31  
7 1     1   5 use warnings;
  1         1  
  1         28  
8              
9 1     1   5 use Carp;
  1         4  
  1         88  
10 1     1   1158 use WWW::Mechanize;
  1         241487  
  1         39  
11 1     1   13 use HTML::TokeParser;
  1         1  
  1         27  
12             use constant {
13 1         86 LOGIN_URL => 'https://wwwtb.psk.at/InternetBanking/sofabanking.html',
14             DETAIL_URL => 'https://wwwtb.psk.at/InternetBanking/InternetBanking/?d=eus&kord=k%011d',
15 1     1   5 };
  1         2  
16             use Class::MethodMaker
17 1         11 new_hash_init => 'new',
18             get_set => [ qw/ account user pass newline _agent / ],
19 1     1   1657 boolean => 'return_floats';
  1         23444  
20              
21             our $VERSION = '1.04';
22              
23              
24             sub check_balance {
25 0     0 1   my $self = shift;
26              
27 0           $self->_connect;
28 0           $self->_parse_summary($self->_agent->content);
29             }
30              
31              
32             sub get_entries {
33 0     0 1   my $self = shift;
34              
35 0           $self->_connect;
36 0           $self->_agent->get(sprintf(DETAIL_URL, $self->account));
37 0           $self->_agent->submit_form(form_number => 1);
38 0           $self->_parse_entries($self->_agent->content);
39             }
40              
41              
42             sub _connect {
43 0     0     my $self = shift;
44              
45 0 0         croak "Need account number to connect.\n" unless $self->account;
46 0 0         croak "Need user to connect.\n" unless $self->user;
47 0 0         croak "Need password to connect.\n" unless $self->pass;
48              
49 0 0         return if ref $self->_agent eq 'WWW::Mechanize';
50              
51             # XXX write tests using the demo account!
52             #$self->_agent->follow('Demo');
53              
54 0           $self->_agent(WWW::Mechanize->new);
55 0           $self->_agent->agent_alias('Mac Safari');
56 0           $self->_agent->get(LOGIN_URL);
57 0           $self->_agent->follow_link(n => 0);
58 0           $self->_agent->form_number(1);
59 0           $self->_agent->field('tn', $self->account);
60 0           $self->_agent->field('vf', $self->user);
61 0           $self->_agent->field('pin', $self->pass);
62 0           $self->_agent->click('Submit');
63             }
64              
65              
66             sub _parse_entries {
67 0     0     my($self, $content) = @_;
68 0   0       my $newline = $self->newline || '; ';
69 0           my $stream;
70             my @result;
71              
72 0           $content =~ s/<[Bb][Rr]>/$newline/go;
73 0           $stream = HTML::TokeParser->new(\$content);
74              
75             # find and skip the table heading of the detail listing.
76 0           for(my $i = 0; $i < 4;) {
77 0           my $class = ($stream->get_tag('td'))->[1]{class};
78              
79 0 0 0       $i++ if defined $class and $class eq 'theader';
80             }
81              
82             # now process the lines...
83 0           while(my $row = $stream->get_tag('td')) {
84 0           my $entry;
85              
86             last unless
87 0 0 0       exists $row->[1]{class} and
88             $row->[1]{class} eq 'tdata';
89              
90             # get nr
91 0           $entry->{nr} = $stream->get_text('/td');
92              
93             # get text
94 0           $stream->get_tag('td');
95 0           $entry->{text} = $stream->get_text('/td');
96 0           $entry->{text} =~ s/($newline)$//;
97              
98             # get value date
99 0           $stream->get_tag('td');
100 0           $entry->{value} = $stream->get_text('/td');
101              
102             # get amount
103 0           $stream->get_tag('td');
104 0           $entry->{amount} = $stream->get_text('/td');
105 0 0         $entry->{amount} = $self->_scalar2float($entry->{amount})
106             if $self->return_floats;
107              
108 0           push @result, $entry;
109             }
110              
111 0           @result;
112             }
113              
114              
115             sub _parse_summary {
116 0     0     my($self, $content) = @_;
117 0           my $stream = HTML::TokeParser->new(\$content);
118 0           my %result;
119              
120             # get every interesting 'subtitle'.
121 0           while($stream->get_tag('span')) {
122 0           my %data;
123 0           my $type = $stream->get_trimmed_text('/span');
124              
125             # catch girokontos.
126 0 0         if($type eq 'Girokonto') {
    0          
127 0           my $tmp;
128              
129             # get name, number and currency of the account.
130 0           $stream->get_tag('a');
131 0           $tmp = $stream->get_text('/a');
132 0           (undef, $data{name}, undef, $tmp) = split(/\n/, $tmp);
133 0           ($data{account}, $data{currency}) = split(/\//, $tmp);
134              
135 0           $data{account} = $self->_cleanup($data{account});
136 0           $data{name} = $self->_cleanup($data{name});
137              
138             # get the balance and the final balance of the account.
139 0           for(qw/balance final/) {
140 0           $stream->get_tag('table');
141 0           $stream->get_tag('td') for 1 .. 2;
142              
143 0           $data{$_} = $stream->get_trimmed_text('/td');
144 0 0         $data{$_} = $self->_scalar2float($data{$_}) if $self->return_floats;
145             }
146              
147 0           push @{$result{accounts}}, \%data;
  0            
148             # catch wertpapierdepots
149             } elsif($type eq 'Wertpapierdepot') {
150             # get name and number of the fund.
151 0           $stream->get_tag('a');
152 0           (undef, $data{name}, undef, $data{fund}) = split(/\n/, $stream->get_text('/a'));
153              
154 0           $data{fund} = $self->_cleanup($data{fund});
155 0           $data{name} = $self->_cleanup($data{name});
156              
157             # get the balance of the fund.
158 0           $stream->get_tag('table');
159 0           $stream->get_tag('td');
160 0           $data{currency} = $stream->get_trimmed_text('/td');
161              
162 0           $stream->get_tag('td');
163 0           $data{balance} = $stream->get_trimmed_text('/td');
164 0 0         $data{balance} = $self->_scalar2float($data{balance}) if $self->return_floats;
165              
166 0           push @{$result{funds}}, \%data;
  0            
167             }
168              
169             }
170              
171 0           \%result;
172             }
173              
174              
175             sub _scalar2float {
176 0     0     my($self, $scalar) = @_;
177              
178 0           $scalar =~ s/\.//g;
179 0           $scalar =~ s/,/\./g;
180              
181 0           return $scalar;
182             }
183              
184              
185             sub _cleanup {
186 0     0     my($self, $string) = @_;
187              
188 0           $string =~ s/^\s+//g;
189 0           $string;
190             }
191              
192              
193             1;