File Coverage

blib/lib/Finance/Bank/Postbank_de.pm
Criterion Covered Total %
statement 79 96 82.2
branch 12 18 66.6
condition 6 9 66.6
subroutine 22 31 70.9
pod 8 18 44.4
total 127 172 73.8


line stmt bran cond sub pod time code
1             package Finance::Bank::Postbank_de;
2              
3 9     9   666271 use 5.006; # we use lexical filehandles now
  9         67  
4 9     9   62 use strict;
  9         23  
  9         223  
5 9     9   58 use warnings;
  9         18  
  9         290  
6 9     9   68 use Carp;
  9         26  
  9         707  
7 9     9   5002 use Moo 2;
  9         103934  
  9         57  
8              
9 9     9   16516 use Time::Local;
  9         15150  
  9         561  
10 9     9   4529 use POSIX 'strftime';
  9         56829  
  9         46  
11              
12 9     9   17496 use Finance::Bank::Postbank_de::Account;
  9         43  
  9         331  
13 9     9   4303 use Finance::Bank::Postbank_de::APIv1;
  9         40  
  9         451  
14 9     9   75 use Encode qw(decode);
  9         20  
  9         914  
15 9     9   69 use Mozilla::CA;
  9         22  
  9         2443  
16              
17             #use IO::Socket::SSL qw(SSL_VERIFY_PEER SSL_VERIFY_NONE);
18              
19             our $VERSION = '0.57';
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   10914 %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 643 my ($self) = @_;
88              
89 7 50       54 $self->close_session()
90             if ($self->session);
91 7         18 my $pb;
92 7         17 my $ok = eval {
93 7         65 $pb = $self->api->login( $self->login, $self->password );
94 4         7106 1
95             };
96 7 100       130 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         40 $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 22 my ($self) = @_;
132 3         28 $self->api->ua->status != 200
133             #return unless $self->agent;
134             #
135             #$self->agent->content =~ m!!sm
136             # or
137             #$self->agent->content =~ m!!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!\s*\s*(.*?)\s*\s*

!sm
148             # or
149             #$self->agent->content =~ m!\s*(.*?)\s*

!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 19 my ($self) = @_;
157             #return unless $self->agent;
158             ##$self->error_page and
159             #$self->agent->content =~ m!Sehr geehrter Online-Banking\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!

\s*\s*Diese Funktion steht auf Grund einer technischen St.*?rung derzeit leider nicht zur Verf.*?gung.*?\s*

!sm # Testumgebung...
162             ()
163 1         3 };
164              
165             sub access_denied {
166 3     3 0 1424 my ($self) = @_;
167 3         19 $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"\.
\s*$!sm
173             # or $message =~ m!^Sie haben zu viele Zeichen in das Feld eingegeben.
\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 2538 my ($self) = @_;
203 2         24 $self->session(undef);
204 2         155 $self->api(undef);
205 2         1690 1
206             };
207              
208             sub finanzstatus {
209 3     3 0 9 my( $self ) = @_;
210 3 100       20 $self->new_session unless $self->session;
211 3         28 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   8 my ($self,%args) = @_;
219            
220 2         8 my $finanzstatus = $self->finanzstatus;
221 2         103 (my $bp) = $finanzstatus->get_businesspartners; # always take the first...
222 2         151 my %numbers;
223             # this currently includes the credit card numbers ...
224 2         17 for my $acc ( $bp->get_accounts() ) {
225 14 100 100     90 $numbers{ $acc->iban } = $acc if (!$acc->is_depot and !$acc->is_mortgage);
226             };
227              
228 2         122 return $self->_account_numbers( \%numbers );
229             }
230              
231             sub account_numbers {
232 1     1 1 7 my ($self,%args) = @_;
233              
234 1   33     10 my $n = $self->_account_numbers || $self->_build_account_numbers;
235            
236 1         3 sort keys %{ $n };
  1         12  
237             };
238              
239             sub get_account_statement {
240 11     11 1 1003455 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     177 my $accounts = $self->_account_numbers || $self->_build_account_numbers;
251              
252 11 100       104 if( ! $args{ account_number }) {
253             # Hopefully we only got one account (?!)
254 1         5 ($args{ account_number }) = keys %$accounts;
255             };
256              
257 11         61 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         108 my $content = $account->transactions_csv();
273 11 100       1819 if( $args{ file }) {
274             open my $fh, '>', $args{ file }
275 1 50       131 or croak "Couldn't create '$args{ file }': $!";
276 1         20 binmode $fh, ':encoding(UTF-8)';
277 1         238 print $fh $content;
278             };
279             #if ($agent->status == 200) {
280 11         43 my $result = $content;
281             # Result is in UTF-8
282 11         151 return Finance::Bank::Postbank_de::Account->parse_statement(content => $result);
283             };
284              
285             sub unread_messages {
286 1     1 1 12 my( $self )= @_;
287 1         5 $self->finanzstatus->available_messages
288             }
289              
290             1;
291             __END__