line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package Finance::Bank::Postbank_de; |
2
|
|
|
|
|
|
|
|
3
|
9
|
|
|
9
|
|
536713
|
use 5.006; # we use lexical filehandles now |
|
9
|
|
|
|
|
56
|
|
4
|
9
|
|
|
9
|
|
46
|
use strict; |
|
9
|
|
|
|
|
15
|
|
|
9
|
|
|
|
|
190
|
|
5
|
9
|
|
|
9
|
|
37
|
use warnings; |
|
9
|
|
|
|
|
13
|
|
|
9
|
|
|
|
|
234
|
|
6
|
9
|
|
|
9
|
|
41
|
use Carp; |
|
9
|
|
|
|
|
18
|
|
|
9
|
|
|
|
|
483
|
|
7
|
9
|
|
|
9
|
|
3948
|
use Moo 2; |
|
9
|
|
|
|
|
83604
|
|
|
9
|
|
|
|
|
45
|
|
8
|
|
|
|
|
|
|
|
9
|
9
|
|
|
9
|
|
13705
|
use Time::Local; |
|
9
|
|
|
|
|
12355
|
|
|
9
|
|
|
|
|
447
|
|
10
|
9
|
|
|
9
|
|
3723
|
use POSIX 'strftime'; |
|
9
|
|
|
|
|
46135
|
|
|
9
|
|
|
|
|
39
|
|
11
|
|
|
|
|
|
|
|
12
|
9
|
|
|
9
|
|
14133
|
use Finance::Bank::Postbank_de::Account; |
|
9
|
|
|
|
|
26
|
|
|
9
|
|
|
|
|
261
|
|
13
|
9
|
|
|
9
|
|
3503
|
use Finance::Bank::Postbank_de::APIv1; |
|
9
|
|
|
|
|
29
|
|
|
9
|
|
|
|
|
328
|
|
14
|
9
|
|
|
9
|
|
60
|
use Encode qw(decode); |
|
9
|
|
|
|
|
15
|
|
|
9
|
|
|
|
|
788
|
|
15
|
9
|
|
|
9
|
|
54
|
use Mozilla::CA; |
|
9
|
|
|
|
|
13
|
|
|
9
|
|
|
|
|
1946
|
|
16
|
|
|
|
|
|
|
|
17
|
|
|
|
|
|
|
#use IO::Socket::SSL qw(SSL_VERIFY_PEER SSL_VERIFY_NONE); |
18
|
|
|
|
|
|
|
|
19
|
|
|
|
|
|
|
our $VERSION = '0.56'; |
20
|
|
|
|
|
|
|
|
21
|
|
|
|
|
|
|
has 'login' => ( |
22
|
|
|
|
|
|
|
is => 'ro', |
23
|
|
|
|
|
|
|
); |
24
|
|
|
|
|
|
|
|
25
|
|
|
|
|
|
|
has 'password' => ( |
26
|
|
|
|
|
|
|
is => 'ro', |
27
|
|
|
|
|
|
|
); |
28
|
|
|
|
|
|
|
|
29
|
|
|
|
|
|
|
has 'urls' => ( |
30
|
|
|
|
|
|
|
is => 'ro', |
31
|
|
|
|
|
|
|
default => sub { {} }, |
32
|
|
|
|
|
|
|
); |
33
|
|
|
|
|
|
|
|
34
|
|
|
|
|
|
|
has 'logger' => ( |
35
|
|
|
|
|
|
|
is => 'ro', |
36
|
|
|
|
|
|
|
default => sub { {} }, |
37
|
|
|
|
|
|
|
); |
38
|
|
|
|
|
|
|
|
39
|
|
|
|
|
|
|
has 'past_days' => ( |
40
|
|
|
|
|
|
|
is => 'ro', |
41
|
|
|
|
|
|
|
default => sub { {} }, |
42
|
|
|
|
|
|
|
); |
43
|
|
|
|
|
|
|
|
44
|
|
|
|
|
|
|
has 'api' => ( |
45
|
|
|
|
|
|
|
is => 'rw', |
46
|
|
|
|
|
|
|
default => sub { |
47
|
|
|
|
|
|
|
my $api = Finance::Bank::Postbank_de::APIv1->new(); |
48
|
|
|
|
|
|
|
$api->configure_ua(); |
49
|
|
|
|
|
|
|
$api |
50
|
|
|
|
|
|
|
}, |
51
|
|
|
|
|
|
|
); |
52
|
|
|
|
|
|
|
|
53
|
|
|
|
|
|
|
has 'session' => ( |
54
|
|
|
|
|
|
|
is => 'rw', |
55
|
|
|
|
|
|
|
); |
56
|
|
|
|
|
|
|
|
57
|
|
|
|
|
|
|
has '_account_numbers' => ( |
58
|
|
|
|
|
|
|
is => 'rw', |
59
|
|
|
|
|
|
|
); |
60
|
|
|
|
|
|
|
|
61
|
|
|
|
|
|
|
our %functions; |
62
|
|
|
|
|
|
|
BEGIN { |
63
|
9
|
|
|
9
|
|
8454
|
%functions = ( |
64
|
|
|
|
|
|
|
quit => [ text_regex => qr'\bBanking\s+beenden\b' ], |
65
|
|
|
|
|
|
|
accountstatement => [ text_regex => qr'\bUms.*?tze\b' ], |
66
|
|
|
|
|
|
|
); |
67
|
|
|
|
|
|
|
}; |
68
|
|
|
|
|
|
|
|
69
|
|
|
|
|
|
|
around BUILDARGS => sub { |
70
|
|
|
|
|
|
|
my ($orig,$class,%args) = @_; |
71
|
|
|
|
|
|
|
|
72
|
|
|
|
|
|
|
croak "Login/Account number must be specified" |
73
|
|
|
|
|
|
|
unless $args{login}; |
74
|
|
|
|
|
|
|
croak "Password/PIN must be specified" |
75
|
|
|
|
|
|
|
unless $args{password}; |
76
|
|
|
|
|
|
|
if( exists $args{ status }) { |
77
|
|
|
|
|
|
|
$args{ logger } = delete $args{ status }; |
78
|
|
|
|
|
|
|
}; |
79
|
|
|
|
|
|
|
|
80
|
|
|
|
|
|
|
$orig->($class, %args); |
81
|
|
|
|
|
|
|
}; |
82
|
|
|
|
|
|
|
|
83
|
0
|
|
|
0
|
0
|
0
|
sub log { $_[0]->logger->(@_); }; |
84
|
0
|
|
|
0
|
0
|
0
|
sub log_httpresult { $_[0]->log("HTTP Code",$_[0]->agent->status,$_[0]->agent->res->headers->as_string . $_[0]->agent->content) }; |
85
|
|
|
|
|
|
|
|
86
|
|
|
|
|
|
|
sub new_session { |
87
|
7
|
|
|
7
|
1
|
728
|
my ($self) = @_; |
88
|
|
|
|
|
|
|
|
89
|
7
|
50
|
|
|
|
44
|
$self->close_session() |
90
|
|
|
|
|
|
|
if ($self->session); |
91
|
7
|
|
|
|
|
16
|
my $pb; |
92
|
7
|
|
|
|
|
14
|
my $ok = eval { |
93
|
7
|
|
|
|
|
55
|
$pb = $self->api->login( $self->login, $self->password ); |
94
|
4
|
|
|
|
|
7091
|
1 |
95
|
|
|
|
|
|
|
}; |
96
|
7
|
100
|
|
|
|
120
|
if( ! $ok ) { |
97
|
|
|
|
|
|
|
#warn sprintf "Got HTTP error %d, message %s", $self->api->ua->status, $self->api->ua->message; |
98
|
|
|
|
|
|
|
#croak $@; |
99
|
|
|
|
|
|
|
} else { |
100
|
4
|
|
|
|
|
33
|
$self->session( $pb ); |
101
|
|
|
|
|
|
|
} |
102
|
|
|
|
|
|
|
}; |
103
|
|
|
|
|
|
|
|
104
|
|
|
|
|
|
|
sub is_security_advice { |
105
|
0
|
|
|
0
|
0
|
0
|
my ($self) = @_; |
106
|
|
|
|
|
|
|
#$self->agent->content() =~ /\bZum\s+Finanzstatus\b/; |
107
|
|
|
|
|
|
|
}; |
108
|
|
|
|
|
|
|
|
109
|
|
|
|
|
|
|
sub is_nutzungshinweis { |
110
|
0
|
|
|
0
|
0
|
0
|
my ($self) = @_; |
111
|
|
|
|
|
|
|
#$self->agent->content() =~ /\bAus Sicherheitsgr.*?nden haben wir einige\b/; |
112
|
|
|
|
|
|
|
}; |
113
|
|
|
|
|
|
|
|
114
|
|
|
|
|
|
|
|
115
|
|
|
|
|
|
|
sub skip_security_advice { |
116
|
0
|
|
|
0
|
0
|
0
|
my ($self) = @_; |
117
|
|
|
|
|
|
|
#$self->log('Skipping security advice page'); |
118
|
|
|
|
|
|
|
#$self->agent->follow_link(text_regex => qr/\bZum\s+Finanzstatus\b/); |
119
|
|
|
|
|
|
|
# $self->agent->content() =~ /Sicherheitshinweis/; |
120
|
|
|
|
|
|
|
}; |
121
|
|
|
|
|
|
|
|
122
|
|
|
|
|
|
|
sub skip_nutzungshinweis { |
123
|
0
|
|
|
0
|
0
|
0
|
my ($self) = @_; |
124
|
|
|
|
|
|
|
#$self->log('Skipping nutzungshinweis page'); |
125
|
|
|
|
|
|
|
#$self->agent->follow_link(text_regex => qr/\bZur\s+Konten.bersicht\b/); |
126
|
|
|
|
|
|
|
# $self->agent->content() =~ /Sicherheitshinweis/; |
127
|
|
|
|
|
|
|
}; |
128
|
|
|
|
|
|
|
|
129
|
|
|
|
|
|
|
sub error_page { |
130
|
|
|
|
|
|
|
# Check if an error page is shown |
131
|
3
|
|
|
3
|
0
|
19
|
my ($self) = @_; |
132
|
3
|
|
|
|
|
23
|
$self->api->ua->status != 200 |
133
|
|
|
|
|
|
|
#return unless $self->agent; |
134
|
|
|
|
|
|
|
# |
135
|
|
|
|
|
|
|
#$self->agent->content =~ m!<p\s+class="form-error">!sm |
136
|
|
|
|
|
|
|
# or |
137
|
|
|
|
|
|
|
#$self->agent->content =~ m!<p\s+class="field-error">!sm |
138
|
|
|
|
|
|
|
# or $self->maintenance; |
139
|
|
|
|
|
|
|
}; |
140
|
|
|
|
|
|
|
|
141
|
|
|
|
|
|
|
sub error_message { |
142
|
0
|
|
|
0
|
0
|
0
|
my ($self) = @_; |
143
|
|
|
|
|
|
|
#return unless $self->agent; |
144
|
|
|
|
|
|
|
#die "No error condition detected in:\n" . $self->agent->content |
145
|
|
|
|
|
|
|
# unless $self->error_page; |
146
|
|
|
|
|
|
|
#if( |
147
|
|
|
|
|
|
|
#$self->agent->content =~ m!<p\s+class="form-error">\s*<strong>\s*(.*?)\s*</strong>\s*</p>!sm |
148
|
|
|
|
|
|
|
# or |
149
|
|
|
|
|
|
|
#$self->agent->content =~ m!<p\s+class="field-error">\s*(.*?)\s*</p>!sm |
150
|
|
|
|
|
|
|
# ) { return $1 } |
151
|
|
|
|
|
|
|
# #or croak "No error message found in:\n" . $self->agent->content; |
152
|
0
|
|
|
|
|
0
|
return '' |
153
|
|
|
|
|
|
|
}; |
154
|
|
|
|
|
|
|
|
155
|
|
|
|
|
|
|
sub maintenance { |
156
|
1
|
|
|
1
|
1
|
18
|
my ($self) = @_; |
157
|
|
|
|
|
|
|
#return unless $self->agent; |
158
|
|
|
|
|
|
|
##$self->error_page and |
159
|
|
|
|
|
|
|
#$self->agent->content =~ m!Sehr geehrter <span lang="en">Online-Banking</span>\s+Nutzer,\s+wegen einer hohen Auslastung kommt es derzeit im Online-Banking zu\s*längeren Wartezeiten.!sm |
160
|
|
|
|
|
|
|
#or $self->agent->content =~ m! Wartung\b! |
161
|
|
|
|
|
|
|
#or $self->agent->content =~ m!<p class="important">\s*<strong>\s*Diese Funktion steht auf Grund einer technischen St.*?rung derzeit leider nicht zur Verf.*?gung.*?</strong>\s*</p>!sm # Testumgebung... |
162
|
|
|
|
|
|
|
() |
163
|
1
|
|
|
|
|
2
|
}; |
164
|
|
|
|
|
|
|
|
165
|
|
|
|
|
|
|
sub access_denied { |
166
|
3
|
|
|
3
|
0
|
1784
|
my ($self) = @_; |
167
|
3
|
|
|
|
|
17
|
$self->api->ua->status == 401 |
168
|
|
|
|
|
|
|
#if ($self->error_page) { |
169
|
|
|
|
|
|
|
# my $message = $self->error_message; |
170
|
|
|
|
|
|
|
# |
171
|
|
|
|
|
|
|
# return ( |
172
|
|
|
|
|
|
|
# $message =~ m!^Die Kontonummer ist nicht für das Internet Online-Banking freigeschaltet. Bitte verwenden Sie zur Freischaltung den Link "Online-Banking freischalten"\.<br />\s*$!sm |
173
|
|
|
|
|
|
|
# or $message =~ m!^Sie haben zu viele Zeichen in das Feld eingegeben.<br />\s*$!sm |
174
|
|
|
|
|
|
|
# or $message =~ m!^Die eingegebene Postbank Girokontonummer ist zu lang. Bitte überprüfen Sie Ihre Eingabe.$!sm |
175
|
|
|
|
|
|
|
# or $message =~ m!^Die Anmeldung ist fehlgeschlagen. Bitte vergewissern Sie sich der Richtigkeit Ihrer Eingaben und f.*?hren Sie den Anmeldevorgang erneut durch.\s*$!sm |
176
|
|
|
|
|
|
|
# ) |
177
|
|
|
|
|
|
|
#} else { |
178
|
|
|
|
|
|
|
# return; |
179
|
|
|
|
|
|
|
#}; |
180
|
|
|
|
|
|
|
}; |
181
|
|
|
|
|
|
|
|
182
|
|
|
|
|
|
|
sub session_timed_out { |
183
|
0
|
|
|
0
|
1
|
0
|
my ($self) = @_; |
184
|
|
|
|
|
|
|
#$self->agent->content =~ /Die Sitzungsdaten sind ungültig, bitte führen Sie einen erneuten Login durch.\s+\(27000\)/; |
185
|
|
|
|
|
|
|
() |
186
|
0
|
|
|
|
|
0
|
}; |
187
|
|
|
|
|
|
|
|
188
|
|
|
|
|
|
|
sub select_function { |
189
|
0
|
|
|
0
|
1
|
0
|
my ($self,$function) = @_; |
190
|
0
|
0
|
|
|
|
0
|
if (! $self->session) { |
191
|
0
|
|
|
|
|
0
|
$self->new_session; |
192
|
|
|
|
|
|
|
}; |
193
|
|
|
|
|
|
|
croak "Unknown account function '$function'" |
194
|
0
|
0
|
|
|
|
0
|
unless exists $functions{$function}; |
195
|
0
|
|
|
|
|
0
|
my $method = $functions{ $function }; |
196
|
|
|
|
|
|
|
|
197
|
0
|
|
|
|
|
0
|
my $res = $self->session->navigate($method); |
198
|
0
|
|
|
|
|
0
|
$res |
199
|
|
|
|
|
|
|
}; |
200
|
|
|
|
|
|
|
|
201
|
|
|
|
|
|
|
sub close_session { |
202
|
2
|
|
|
2
|
1
|
2562
|
my ($self) = @_; |
203
|
2
|
|
|
|
|
22
|
$self->session(undef); |
204
|
2
|
|
|
|
|
188
|
$self->api(undef); |
205
|
2
|
|
|
|
|
1137
|
1 |
206
|
|
|
|
|
|
|
}; |
207
|
|
|
|
|
|
|
|
208
|
|
|
|
|
|
|
sub finanzstatus { |
209
|
3
|
|
|
3
|
0
|
8
|
my( $self ) = @_; |
210
|
3
|
100
|
|
|
|
16
|
$self->new_session unless $self->session; |
211
|
3
|
|
|
|
|
26
|
my $finanzstatus = $self->session->navigate( |
212
|
|
|
|
|
|
|
class => 'Finance::Bank::Postbank_de::APIv1::Finanzstatus', |
213
|
|
|
|
|
|
|
path => ['banking_v1' => 'financialstatus'] |
214
|
|
|
|
|
|
|
); |
215
|
|
|
|
|
|
|
} |
216
|
|
|
|
|
|
|
|
217
|
|
|
|
|
|
|
sub _build_account_numbers { |
218
|
2
|
|
|
2
|
|
6
|
my ($self,%args) = @_; |
219
|
|
|
|
|
|
|
|
220
|
2
|
|
|
|
|
7
|
my $finanzstatus = $self->finanzstatus; |
221
|
2
|
|
|
|
|
91
|
(my $bp) = $finanzstatus->get_businesspartners; # always take the first... |
222
|
2
|
|
|
|
|
107
|
my %numbers; |
223
|
|
|
|
|
|
|
# this currently includes the credit card numbers ... |
224
|
2
|
|
|
|
|
13
|
for my $acc ( $bp->get_accounts() ) { |
225
|
14
|
100
|
100
|
|
|
106
|
$numbers{ $acc->iban } = $acc if ($acc->productType ne 'DEPOT' and $acc->productType ne 'BAUFINANZIERUNG'); |
226
|
|
|
|
|
|
|
}; |
227
|
|
|
|
|
|
|
|
228
|
2
|
|
|
|
|
92
|
return $self->_account_numbers( \%numbers ); |
229
|
|
|
|
|
|
|
} |
230
|
|
|
|
|
|
|
|
231
|
|
|
|
|
|
|
sub account_numbers { |
232
|
1
|
|
|
1
|
1
|
7
|
my ($self,%args) = @_; |
233
|
|
|
|
|
|
|
|
234
|
1
|
|
33
|
|
|
11
|
my $n = $self->_account_numbers || $self->_build_account_numbers; |
235
|
|
|
|
|
|
|
|
236
|
1
|
|
|
|
|
3
|
sort keys %{ $n }; |
|
1
|
|
|
|
|
10
|
|
237
|
|
|
|
|
|
|
}; |
238
|
|
|
|
|
|
|
|
239
|
|
|
|
|
|
|
sub get_account_statement { |
240
|
11
|
|
|
11
|
1
|
4267
|
my ($self,%args) = @_; |
241
|
|
|
|
|
|
|
|
242
|
|
|
|
|
|
|
#my $past_days = $args{past_days} || $self->{past_days}; |
243
|
|
|
|
|
|
|
#if($past_days) { |
244
|
|
|
|
|
|
|
# my ($day, $month, $year) = split/\./, $agent->current_form->value('umsatzanzeigeGiro:salesForm:umsatzFilterOptionenAufklappbarSuchfeldPanel:accordion:vonBisDatum:datumForm:bisGruppe:bisDatum'); |
245
|
|
|
|
|
|
|
# my $end_epoch = timegm(0, 0, 0, $day, $month-1, $year); |
246
|
|
|
|
|
|
|
# my $from_date = strftime '%d.%m.%Y', localtime($end_epoch-($past_days-1)*60*60*24); |
247
|
|
|
|
|
|
|
# $agent->current_form->value('umsatzanzeigeGiro:salesForm:umsatzFilterOptionenAufklappbarSuchfeldPanel:accordion:vonBisDatum:datumForm:vonGruppe:vonDatum' => $from_date); |
248
|
|
|
|
|
|
|
#}; |
249
|
|
|
|
|
|
|
|
250
|
11
|
|
66
|
|
|
63
|
my $accounts = $self->_account_numbers || $self->_build_account_numbers; |
251
|
|
|
|
|
|
|
|
252
|
11
|
100
|
|
|
|
34
|
if( ! $args{ account_number }) { |
253
|
|
|
|
|
|
|
# Hopefully we only got one account (?!) |
254
|
1
|
|
|
|
|
4
|
($args{ account_number }) = keys %$accounts; |
255
|
|
|
|
|
|
|
}; |
256
|
|
|
|
|
|
|
|
257
|
11
|
|
|
|
|
28
|
my $account = $accounts->{ $args{ account_number }}; |
258
|
|
|
|
|
|
|
|
259
|
|
|
|
|
|
|
#if (exists $args{account_number}) { |
260
|
|
|
|
|
|
|
# $self->log("Getting account statement for $args{account_number}"); |
261
|
|
|
|
|
|
|
# # Load the account numbers if not already loaded |
262
|
|
|
|
|
|
|
# $self->account_numbers; |
263
|
|
|
|
|
|
|
# if(! exists $self->{account_numbers}->{$args{account_number}}) { |
264
|
|
|
|
|
|
|
# croak "Unknown account number '$args{account_number}'"; |
265
|
|
|
|
|
|
|
# }; |
266
|
|
|
|
|
|
|
# my $index = $self->{account_numbers}->{$args{account_number}}; |
267
|
|
|
|
|
|
|
# $agent->current_form->param( 'selectForm:kontoauswahl' => $index ); |
268
|
|
|
|
|
|
|
#} else { |
269
|
|
|
|
|
|
|
# my @accounts = $agent->current_form->value('selectForm:kontoauswahl'); |
270
|
|
|
|
|
|
|
# $self->log("Getting account statement via default (@accounts)"); |
271
|
|
|
|
|
|
|
#}; |
272
|
11
|
|
|
|
|
49
|
my $content = $account->transactions_csv(); |
273
|
11
|
100
|
|
|
|
1254
|
if( $args{ file }) { |
274
|
|
|
|
|
|
|
open my $fh, '>', $args{ file } |
275
|
1
|
50
|
|
|
|
102
|
or croak "Couldn't create '$args{ file }': $!"; |
276
|
1
|
|
|
|
|
18
|
binmode $fh, ':encoding(UTF-8)'; |
277
|
1
|
|
|
|
|
232
|
print $fh $content; |
278
|
|
|
|
|
|
|
}; |
279
|
|
|
|
|
|
|
#if ($agent->status == 200) { |
280
|
11
|
|
|
|
|
34
|
my $result = $content; |
281
|
|
|
|
|
|
|
# Result is in UTF-8 |
282
|
11
|
|
|
|
|
109
|
return Finance::Bank::Postbank_de::Account->parse_statement(content => $result); |
283
|
|
|
|
|
|
|
}; |
284
|
|
|
|
|
|
|
|
285
|
|
|
|
|
|
|
sub unread_messages { |
286
|
1
|
|
|
1
|
1
|
9
|
my( $self )= @_; |
287
|
1
|
|
|
|
|
6
|
$self->finanzstatus->available_messages |
288
|
|
|
|
|
|
|
} |
289
|
|
|
|
|
|
|
|
290
|
|
|
|
|
|
|
1; |
291
|
|
|
|
|
|
|
__END__ |
292
|
|
|
|
|
|
|
|
293
|
|
|
|
|
|
|
=encoding ISO8859-1 |
294
|
|
|
|
|
|
|
|
295
|
|
|
|
|
|
|
=head1 NAME |
296
|
|
|
|
|
|
|
|
297
|
|
|
|
|
|
|
Finance::Bank::Postbank_de - Check your Postbank.de bank account from Perl |
298
|
|
|
|
|
|
|
|
299
|
|
|
|
|
|
|
=head1 SYNOPSIS |
300
|
|
|
|
|
|
|
|
301
|
|
|
|
|
|
|
=for example begin |
302
|
|
|
|
|
|
|
|
303
|
|
|
|
|
|
|
use strict; |
304
|
|
|
|
|
|
|
require Crypt::SSLeay; # It's a prerequisite |
305
|
|
|
|
|
|
|
use Finance::Bank::Postbank_de; |
306
|
|
|
|
|
|
|
my $account = Finance::Bank::Postbank_de->new( |
307
|
|
|
|
|
|
|
login => 'Petra.Pfiffig', |
308
|
|
|
|
|
|
|
password => '123456789', |
309
|
|
|
|
|
|
|
status => sub { shift; |
310
|
|
|
|
|
|
|
print join(" ", @_),"\n" |
311
|
|
|
|
|
|
|
if ($_[0] eq "HTTP Code") |
312
|
|
|
|
|
|
|
and ($_[1] != 200) |
313
|
|
|
|
|
|
|
or ($_[0] ne "HTTP Code"); |
314
|
|
|
|
|
|
|
|
315
|
|
|
|
|
|
|
}, |
316
|
|
|
|
|
|
|
); |
317
|
|
|
|
|
|
|
# Retrieve account data : |
318
|
|
|
|
|
|
|
my $retrieved_statement = $account->get_account_statement(); |
319
|
|
|
|
|
|
|
print "Statement date : ",$retrieved_statement->balance->[0],"\n"; |
320
|
|
|
|
|
|
|
print "Balance : ",$retrieved_statement->balance->[1]," EUR\n"; |
321
|
|
|
|
|
|
|
|
322
|
|
|
|
|
|
|
# Output CSV for the transactions |
323
|
|
|
|
|
|
|
for my $row ($retrieved_statement->transactions) { |
324
|
|
|
|
|
|
|
print join( ";", map { $row->{$_} } (qw( tradedate valuedate type comment receiver sender amount ))),"\n"; |
325
|
|
|
|
|
|
|
}; |
326
|
|
|
|
|
|
|
|
327
|
|
|
|
|
|
|
$account->close_session; |
328
|
|
|
|
|
|
|
# See Finance::Bank::Postbank_de::Account for |
329
|
|
|
|
|
|
|
# a simpler example |
330
|
|
|
|
|
|
|
|
331
|
|
|
|
|
|
|
=for example end |
332
|
|
|
|
|
|
|
|
333
|
|
|
|
|
|
|
=for example_testing |
334
|
|
|
|
|
|
|
isa_ok($account,"Finance::Bank::Postbank_de"); |
335
|
|
|
|
|
|
|
isa_ok($retrieved_statement,"Finance::Bank::Postbank_de::Account"); |
336
|
|
|
|
|
|
|
$::_STDOUT_ =~ s!^Statement date : \d{8}\n!!m; |
337
|
|
|
|
|
|
|
$::_STDOUT_ =~ s!^Skipping security advice page\n!!m; |
338
|
|
|
|
|
|
|
my $expected = <<EOX; |
339
|
|
|
|
|
|
|
New Finance::Bank::Postbank_de created |
340
|
|
|
|
|
|
|
Connecting to https://banking.postbank.de/app/welcome.do |
341
|
|
|
|
|
|
|
Activating (?-xism:^Kontoums.*?tze\$) |
342
|
|
|
|
|
|
|
Getting account statement via default (9999999999) |
343
|
|
|
|
|
|
|
Downloading text version |
344
|
|
|
|
|
|
|
Statement date : ???????? |
345
|
|
|
|
|
|
|
Balance : 5314.05 EUR |
346
|
|
|
|
|
|
|
.berweisung;111111/1000000000/37050198 FINANZKASSE 3991234 STEUERNUMMER 00703434;Finanzkasse K.ln-S.d;PETRA PFIFFIG;-328.75 |
347
|
|
|
|
|
|
|
.berweisung;111111/3299999999/20010020 .BERTRAG AUF SPARCARD 3299999999;Petra Pfiffig;PETRA PFIFFIG;-228.61 |
348
|
|
|
|
|
|
|
Gutschrift;BEZ.GE PERS.NR. 70600170/01 ARBEITGEBER U. CO;PETRA PFIFFIG;Petra Pfiffig;2780.70 |
349
|
|
|
|
|
|
|
.berweisung;DA 1000001;Verlagshaus Scribere GmbH;PETRA PFIFFIG;-31.50 |
350
|
|
|
|
|
|
|
Scheckeinreichung;EINGANG VORBEHALTEN GUTBUCHUNG 12345;PETRA PFIFFIG;Ein Fremder;1830.00 |
351
|
|
|
|
|
|
|
Lastschrift;MIETE 600+250 EUR OBJ22/328 SCHULSTR.7, 12345 MEINHEIM;Eigenheim KG;PETRA PFIFFIG;-850.00 |
352
|
|
|
|
|
|
|
Inh. Scheck;;2000123456789;PETRA PFIFFIG;-75.00 |
353
|
|
|
|
|
|
|
Lastschrift;TEILNEHMERNR 1234567 RUNDFUNK 0103-1203;GEZ;PETRA PFIFFIG;-84.75 |
354
|
|
|
|
|
|
|
Lastschrift;RECHNUNG 03121999;Telefon AG Köln;PETRA PFIFFIG;-125.80 |
355
|
|
|
|
|
|
|
Lastschrift;STROMKOSTEN KD.NR.1462347 JAHRESABRECHNUNG;Stadtwerke Musterstadt;PETRA PFIFFIG;-580.06 |
356
|
|
|
|
|
|
|
Gutschrift;KINDERGELD KINDERGELD-NR. 1462347;PETRA PFIFFIG;Arbeitsamt Bonn;154.00 |
357
|
|
|
|
|
|
|
Closing session |
358
|
|
|
|
|
|
|
Activating (?-xism:^Banking beenden\$) |
359
|
|
|
|
|
|
|
EOX |
360
|
|
|
|
|
|
|
for ($::_STDOUT_,$expected) { |
361
|
|
|
|
|
|
|
s!\r\n!\n!gsm; |
362
|
|
|
|
|
|
|
s![\x80-\xff]!.!gsm; |
363
|
|
|
|
|
|
|
# Strip out all date references ... |
364
|
|
|
|
|
|
|
s/^\d{8};\d{8};//gm; |
365
|
|
|
|
|
|
|
}; |
366
|
|
|
|
|
|
|
my @got = split /\n/, $::_STDOUT_; |
367
|
|
|
|
|
|
|
my @expected = split /\n/, $expected; |
368
|
|
|
|
|
|
|
is_deeply(\@got,\@expected,'Retrieving an account statement works') |
369
|
|
|
|
|
|
|
or do { |
370
|
|
|
|
|
|
|
diag "--- Got"; |
371
|
|
|
|
|
|
|
diag $::_STDOUT_; |
372
|
|
|
|
|
|
|
diag "--- Expected"; |
373
|
|
|
|
|
|
|
diag $expected; |
374
|
|
|
|
|
|
|
}; |
375
|
|
|
|
|
|
|
|
376
|
|
|
|
|
|
|
=head1 DESCRIPTION |
377
|
|
|
|
|
|
|
|
378
|
|
|
|
|
|
|
This module provides a rudimentary interface to the Postbank online banking system at |
379
|
|
|
|
|
|
|
https://meine.postbank.de/. |
380
|
|
|
|
|
|
|
|
381
|
|
|
|
|
|
|
The interface was cooked up by me without taking a look at the other Finance::Bank |
382
|
|
|
|
|
|
|
modules. If you have any proposals for a change, they are welcome ! |
383
|
|
|
|
|
|
|
|
384
|
|
|
|
|
|
|
=head1 WARNING |
385
|
|
|
|
|
|
|
|
386
|
|
|
|
|
|
|
This is code for online banking, and that means your money, and that means BE CAREFUL. You are encouraged, nay, expected, to audit the source of this module yourself to reassure yourself that I am not doing anything untoward with your banking data. This software is useful to me, but is provided under NO GUARANTEE, explicit or implied. |
387
|
|
|
|
|
|
|
|
388
|
|
|
|
|
|
|
=head1 WARNUNG |
389
|
|
|
|
|
|
|
|
390
|
|
|
|
|
|
|
Dieser Code beschaeftigt sich mit Online Banking, das heisst, hier geht es um Dein Geld und das bedeutet SEI VORSICHTIG ! Ich gehe |
391
|
|
|
|
|
|
|
davon aus, dass Du den Quellcode persoenlich anschaust, um Dich zu vergewissern, dass ich nichts unrechtes mit Deinen Bankdaten |
392
|
|
|
|
|
|
|
anfange. Diese Software finde ich persoenlich nuetzlich, aber ich stelle sie OHNE JEDE GARANTIE zur Verfuegung, weder eine |
393
|
|
|
|
|
|
|
ausdrueckliche noch eine implizierte Garantie. |
394
|
|
|
|
|
|
|
|
395
|
|
|
|
|
|
|
=head1 METHODS |
396
|
|
|
|
|
|
|
|
397
|
|
|
|
|
|
|
=head2 new |
398
|
|
|
|
|
|
|
|
399
|
|
|
|
|
|
|
Creates a new object. It takes three named parameters : |
400
|
|
|
|
|
|
|
|
401
|
|
|
|
|
|
|
=over 4 |
402
|
|
|
|
|
|
|
|
403
|
|
|
|
|
|
|
=item login => 'Petra.Pfiffig' |
404
|
|
|
|
|
|
|
|
405
|
|
|
|
|
|
|
This is your Postbank ID account name. |
406
|
|
|
|
|
|
|
|
407
|
|
|
|
|
|
|
=item password => '123456789' |
408
|
|
|
|
|
|
|
|
409
|
|
|
|
|
|
|
This is your PIN / password. |
410
|
|
|
|
|
|
|
|
411
|
|
|
|
|
|
|
=item status => sub {} |
412
|
|
|
|
|
|
|
|
413
|
|
|
|
|
|
|
This is an optional |
414
|
|
|
|
|
|
|
parameter where you can specify a callback that will receive the messages the object |
415
|
|
|
|
|
|
|
Finance::Bank::Postbank produces per session. |
416
|
|
|
|
|
|
|
|
417
|
|
|
|
|
|
|
=back |
418
|
|
|
|
|
|
|
|
419
|
|
|
|
|
|
|
=head2 $account->new_session |
420
|
|
|
|
|
|
|
|
421
|
|
|
|
|
|
|
Closes the current session and logs in to the website using |
422
|
|
|
|
|
|
|
the credentials given at construction time. |
423
|
|
|
|
|
|
|
|
424
|
|
|
|
|
|
|
=head2 $account->close_session |
425
|
|
|
|
|
|
|
|
426
|
|
|
|
|
|
|
Closes the session and invalidates it on the server. |
427
|
|
|
|
|
|
|
|
428
|
|
|
|
|
|
|
=head2 $account->agent |
429
|
|
|
|
|
|
|
|
430
|
|
|
|
|
|
|
Returns the C<WWW::Mechanize> object. You can retrieve the |
431
|
|
|
|
|
|
|
content of the current page from there. |
432
|
|
|
|
|
|
|
|
433
|
|
|
|
|
|
|
=head2 C<< $session->account_numbers >> |
434
|
|
|
|
|
|
|
|
435
|
|
|
|
|
|
|
Returns the account numbers. Only numeric account numbers |
436
|
|
|
|
|
|
|
are returned - the credit card account numbers are not |
437
|
|
|
|
|
|
|
returned. |
438
|
|
|
|
|
|
|
|
439
|
|
|
|
|
|
|
=head2 $account->select_function STRING |
440
|
|
|
|
|
|
|
|
441
|
|
|
|
|
|
|
Selects a function. The currently supported functions are |
442
|
|
|
|
|
|
|
|
443
|
|
|
|
|
|
|
accountstatement |
444
|
|
|
|
|
|
|
quit |
445
|
|
|
|
|
|
|
|
446
|
|
|
|
|
|
|
=head2 $account->get_account_statement |
447
|
|
|
|
|
|
|
|
448
|
|
|
|
|
|
|
Navigates to the print version of the account statement. The content can currently |
449
|
|
|
|
|
|
|
be retrieved from the agent, but this will most likely change, as the print version |
450
|
|
|
|
|
|
|
of the account statement is not a navigable page. The result of the function |
451
|
|
|
|
|
|
|
is either undef or a Finance::Bank::Postbank_de::Account object. |
452
|
|
|
|
|
|
|
|
453
|
|
|
|
|
|
|
C<past_days> - Number of days in the past to request the statement for |
454
|
|
|
|
|
|
|
The default is 10. |
455
|
|
|
|
|
|
|
|
456
|
|
|
|
|
|
|
=head2 $account->unread_messages |
457
|
|
|
|
|
|
|
|
458
|
|
|
|
|
|
|
Returns the number of unread messages. There is no way |
459
|
|
|
|
|
|
|
to retrieve the messages themselves yet. |
460
|
|
|
|
|
|
|
|
461
|
|
|
|
|
|
|
=head2 session_timed_out |
462
|
|
|
|
|
|
|
|
463
|
|
|
|
|
|
|
Returns true if our banking session timed out. |
464
|
|
|
|
|
|
|
|
465
|
|
|
|
|
|
|
=head2 maintenance |
466
|
|
|
|
|
|
|
|
467
|
|
|
|
|
|
|
Returns true if the banking interface is currently unavailable due to maintenance. |
468
|
|
|
|
|
|
|
|
469
|
|
|
|
|
|
|
=head1 AUTHOR |
470
|
|
|
|
|
|
|
|
471
|
|
|
|
|
|
|
Max Maischein, E<lt>corion@cpan.orgE<gt> |
472
|
|
|
|
|
|
|
|
473
|
|
|
|
|
|
|
=head1 SEE ALSO |
474
|
|
|
|
|
|
|
|
475
|
|
|
|
|
|
|
L<perl>, L<WWW::Mechanize>. |
476
|
|
|
|
|
|
|
|
477
|
|
|
|
|
|
|
=head1 REPOSITORY |
478
|
|
|
|
|
|
|
|
479
|
|
|
|
|
|
|
The public repository of this module is |
480
|
|
|
|
|
|
|
L<https://github.com/Corion/Finance-Bank-Postbank_de>. |
481
|
|
|
|
|
|
|
|
482
|
|
|
|
|
|
|
=head1 SUPPORT |
483
|
|
|
|
|
|
|
|
484
|
|
|
|
|
|
|
The public support forum of this module is |
485
|
|
|
|
|
|
|
L<https://perlmonks.org/>. |
486
|
|
|
|
|
|
|
|
487
|
|
|
|
|
|
|
=head1 BUG TRACKER |
488
|
|
|
|
|
|
|
|
489
|
|
|
|
|
|
|
Please report bugs in this module via the RT CPAN bug queue at |
490
|
|
|
|
|
|
|
L<https://rt.cpan.org/Public/Dist/Display.html?Name=Finance-Bank-Postbank_de> |
491
|
|
|
|
|
|
|
or via mail to L<finance-bank-postbank_de-Bugs@rt.cpan.org>. |
492
|
|
|
|
|
|
|
|
493
|
|
|
|
|
|
|
=head1 COPYRIGHT (c) |
494
|
|
|
|
|
|
|
|
495
|
|
|
|
|
|
|
Copyright 2003-2018 by Max Maischein C<corion@cpan.org>. |
496
|
|
|
|
|
|
|
|
497
|
|
|
|
|
|
|
=head1 LICENSE |
498
|
|
|
|
|
|
|
|
499
|
|
|
|
|
|
|
This module is released under the same terms as Perl itself. |
500
|
|
|
|
|
|
|
|
501
|
|
|
|
|
|
|
=cut |