File Coverage

blib/lib/Akado/Account.pm
Criterion Covered Total %
statement 22 24 91.6
branch n/a
condition n/a
subroutine 8 8 100.0
pod n/a
total 30 32 93.7


line stmt bran cond sub pod time code
1             package Akado::Account;
2             {
3             $Akado::Account::VERSION = '1.2.0';
4             }
5              
6             # ABSTRACT: get internet provider Akado account info
7              
8 2     2   165362 use strict;
  2         7  
  2         755  
9 2     2   15 use warnings FATAL => 'all';
  2         5  
  2         94  
10 2     2   5799 use utf8;
  2         33  
  2         1251  
11              
12 2     2   726 use Carp;
  2         4  
  2         1443  
13 2     2   14 use Digest::MD5 qw(md5_hex);
  2         4  
  2         139  
14 2     2   380432 use HTTP::Request::Common;
  2         457794  
  2         251  
15 2     2   7713 use LWP;
  2         171601  
  2         91  
16 2     2   16187 use XML::XPath;
  0            
  0            
17              
18              
19             sub new {
20             my ($class, $self) = @_;
21              
22             croak 'No login specified, stopped' unless $self->{login};
23             croak 'No password specified, stopped' unless $self->{password};
24              
25             $self->{site} ||= 'https://office.akado.ru/';
26              
27             bless($self, $class);
28             return $self;
29             }
30              
31              
32             sub get_balance {
33             my ($self) = @_;
34              
35             my $data = $self->_get_cached_parsed_data();
36             return $data->{balance};
37             }
38              
39              
40             sub get_next_month_payment {
41             my ($self) = @_;
42              
43             my $data = $self->_get_cached_parsed_data();
44             return $data->{next_month_payment};
45             }
46              
47              
48             sub _get_cached_parsed_data {
49             my ($self) = @_;
50              
51             if (not defined $self->{_parsed_data}) {
52             my $xml = $self->_get_full_account_info_xml();
53             $self->{_parsed_data} = $self->_parse_xml($xml);
54             }
55              
56             return $self->{_parsed_data};
57             }
58              
59              
60             sub _get_full_account_info_xml {
61             my ($self) = @_;
62              
63             my $browser = LWP::UserAgent->new;
64             $browser->agent("Akado::Account/$Akado::Account::VERSION");
65             $browser->cookie_jar( {} );
66              
67             # At first we need to login to the site.
68             # Here we POST login/password and recieve session cookies that are stored
69             # in the UserAgent cookie_jar.
70             my $auth_response = $self->_get_auth_response($browser);
71              
72             # Here we get account data using session cookies that we got at the
73             # previous step
74             my $data_response = $self->_get_data_response($browser);
75              
76             my $xml = $data_response->decoded_content;
77              
78             return $xml;
79             }
80              
81              
82             sub _parse_xml {
83             my ($self, $xml) = @_;
84              
85             my $xp = XML::XPath->new( xml => $xml );
86              
87             my $balance = $xp->findnodes('//bill[contains(@description, "Остаток на счете на")]/@amount')->[0]->getNodeValue();
88             my $next_month_payment = $xp->findnodes('//bill[@description="Стоимость услуг в следующем календарном месяце"]/@amount')->[0]->getNodeValue();
89              
90             my $parsed_account_info = {
91             balance => $balance,
92             next_month_payment => $next_month_payment,
93             };
94              
95             return $parsed_account_info;
96             }
97              
98              
99             sub _get_auth_response {
100             my ($self, $browser) = @_;
101              
102             my $url = $self->{site} . "/user/login.xml";
103              
104             my $request = POST($url,
105             Content => [
106             login => $self->{login},
107             password => $self->{password},
108             ]
109             );
110              
111             my $response = $browser->request($request);
112             $self->_check_response($response);
113              
114             return $response;
115             }
116              
117              
118             sub _get_data_response {
119             my ($self, $browser) = @_;
120              
121             # To get from Akado site data in xml format we need to add cookie render
122             # with the value 'xml'
123             $browser->{cookie_jar}->set_cookie(
124             0, # version
125             'render', # key
126             'xml', # value
127             '/', # $path
128             $self->_get_domain_from_cookies($browser->{cookie_jar}), # domain
129             );
130              
131             my $url = $self->{site} . "/finance/display.xml";
132              
133             my $request = HTTP::Request->new(
134             'GET',
135             $url,
136             );
137              
138             my $response = $browser->request($request);
139             $self->_check_response($response);
140              
141             return $response;
142             }
143              
144              
145             sub _get_domain_from_cookies {
146             my ($self, $cookies) = @_;
147              
148             my $domain;
149              
150             $cookies->scan(
151             sub {
152             $domain = $_[4];
153             }
154             );
155              
156             return $domain
157             }
158              
159              
160             sub _check_response {
161             my ($self, $response) = @_;
162              
163             my $url = scalar $response->request->uri->canonical;
164             if ($response->is_error) {
165             croak "Can't get url '$url'. Got error "
166             . $response->status_line;
167             }
168              
169             return '';
170             }
171              
172              
173             1;
174              
175             __END__