File Coverage

lib/Finance/Bank/HDFC.pm
Criterion Covered Total %
statement 77 93 82.8
branch 16 32 50.0
condition 1 3 33.3
subroutine 14 14 100.0
pod 0 6 0.0
total 108 148 72.9


line stmt bran cond sub pod time code
1             package Finance::Bank::HDFC;
2 1     1   821 use strict; use warnings;
  1     1   1  
  1         33  
  1         4  
  1         1  
  1         44  
3              
4             ###########################################################################
5             # Copyright (C) 2008 by Rohan Almeida
6             #
7             # This library is free software; you can redistribute it and/or modify
8             # it under the same terms as Perl itself.
9             ###########################################################################
10              
11 1     1   810 use version; our $VERSION = qv('0.14');
  1         2049  
  1         5  
12              
13 1     1   813 use Readonly;
  1         2872  
  1         51  
14 1     1   1028 use LWP::UserAgent;
  1         73401  
  1         38  
15 1     1   913 use Template::Extract;
  1         646  
  1         24  
16 1     1   6 use URI::Escape;
  1         2  
  1         77  
17 1     1   1035 use Data::Dumper;
  1         6630  
  1         1283  
18              
19             #use LWP::Debug qw(+ -conns);
20              
21             # Netbanking URL
22             Readonly my $HDFC_URL => 'https://netbanking.hdfcbank.com/netbanking/entry';
23              
24             # Transaction Codes
25             Readonly my %TRANSACTION_CODES => (
26             login => 'LGN',
27             balance => 'SBI',
28             logout => 'LGF',
29             mini_statement => 'SIN',
30             );
31              
32             # HTTP timeout in seconds (default value)
33             Readonly my $HTTP_TIMEOUT => 30;
34              
35             # template for extracting mini statements
36             Readonly my $TEMPLATE_MINI_STATEMENT => <<'EOF';
37             [% FOREACH record %]
38             [% ... %]dattxn[l_count] = '[% date_transaction %]';
39             [% ... %]txndesc[l_count] = "[% description %]";
40             [% ... %]refchqnbr[l_count] = '[% ref_chq_num %]';
41             [% ... %]datvalue[l_count] = '[% date_value %]';
42             [% ... %]amttxn[l_count] = '[% amount %]';
43             [% ... %]balaftertxn[l_count] = '[% balance %]';
44             [% ... %]coddrcr[l_count] = '[% type %]';
45             [% END %]
46             EOF
47              
48              
49             ### CLASS METHOD ####################################################
50             # Usage : $obj = Finance::Bank::HDFC->new()
51             # Purpose : Creates a new F::B::H object
52             # Returns : A F::B::H object
53             # Parameters : None
54             # Throws : no exceptions
55             # Comments : none
56             # See Also : n/a
57             #######################################################################
58             sub new {
59 1     1 0 420 my $class = shift;
60              
61 1         12 my $ua = LWP::UserAgent->new;
62 1         4553 $ua->timeout($HTTP_TIMEOUT);
63              
64 1         45 my $request = HTTP::Request->new( POST => $HDFC_URL );
65 1         9842 $request->content_type('application/x-www-form-urlencoded');
66              
67 1         56 my $self = {
68             'ua' => $ua,
69             'request' => $request,
70             'session_id' => q{},
71             'acct_no' => q{},
72             };
73              
74 1         6 bless $self, $class;
75 1         10 return $self;
76             }
77              
78             ### INSTANCE METHOD ##################################################
79             # Usage :
80             # : $obj->login({
81             # : cust_id => 'xxx',
82             # : password => 'xxx',
83             # : });
84             # Purpose : Login to the netbanking system
85             # Returns : 1 on success
86             # Parameters : A hash ref with keys:
87             # : cust_id => HDFC customer ID
88             # : password => Netbanking PIN
89             # Throws :
90             # : * "Incorrect parameters for method\n"
91             # : * "HTTP error while logging in\n"
92             # : * "Got an invalid HTTP response code: $code\n"
93             # : * "Could not get session ID\n"
94             # Comments : none
95             # See Also : n/a
96             #######################################################################
97             sub login {
98 1     1 0 443 my ( $self, %args ) = @_;
99              
100 1 50 33     8 if ( not exists $args{'cust_id'} || not exists $args{'password'} ) {
101 0         0 die "Incorrect parameters for method\n";
102             }
103              
104 1         9 my $transaction_id = $TRANSACTION_CODES{'login'};
105              
106             # Build request content
107 1         35 $self->{'request'}->content( "fldLoginUserId="
108             . $args{'cust_id'} . '&'
109             . "fldPassword="
110             . $args{'password'} . '&'
111             . "fldAppId=RS" . '&'
112             . "fldTxnId=$transaction_id" . '&'
113             . "fldScrnSeqNbr=01" . '&'
114             . "fldLangId=eng&fldDeviceId=01&fldWebserverId=YG&fldAppServerId=ZZ"
115             );
116              
117 1         35 my $response = $self->{'ua'}->request( $self->{'request'} );
118              
119 1 50       114 if ( $response->is_error ) {
120 0         0 die "HTTP error while logging in\n";
121             }
122              
123 1 50       15 if ( $response->code != 200 ) {
124 0         0 die "Got invalid HTTP response code: " . $response->code . "\n";
125             }
126              
127             # Get session Id
128 1 50       15 if ( $response->content =~
129             // )
130             {
131 1         31 $self->{'session_id'} = $1;
132             }
133             else {
134 0         0 die "Could not get session ID\n";
135             }
136              
137 1         15 return 1;
138             }
139              
140             ### INSTANCE METHOD ##################################################
141             # Usage : $balance = $obj->get_balance()
142             # Purpose : Get balance for default account
143             # Returns :
144             # : 1) $balance => Account balance
145             # Parameters : None
146             # Throws :
147             # : * "Not logged in\n"
148             # : * "HTTP error while getting account balance\n"
149             # : * "Got an invalid HTTP response code: $code\n"
150             # : * "Parse error while getting account balance\n"
151             # Comments :
152             # : * Does not support multiple accounts
153             # See Also : n/a
154             #######################################################################
155             sub get_balance {
156 1     1 0 557 my ($self) = @_;
157              
158             # Check that user has logged in
159 1 50       5 if ( $self->{'session_id'} eq q{} ) {
160 0         0 die "Not logged in\n";
161             }
162              
163             # Get the account balance
164 1         5 my $transaction_id = $TRANSACTION_CODES{'balance'};
165              
166 1         14 $self->{'request'}->content( "fldSessionId="
167             . $self->{'session_id'} . '&'
168             . "fldAppId=RS" . '&'
169             . "fldTxnId=$transaction_id" . '&'
170             . "fldScrnSeqNbr=01" . '&'
171             . "fldModule=CH" );
172              
173 1         19 my $response = $self->{'ua'}->request( $self->{'request'} );
174              
175 1 50       53 if ( $response->is_error ) {
176 0         0 die "HTTP error while getting account balance\n";
177             }
178              
179 1 50       13 if ( $response->code != 200 ) {
180 0         0 die "Got invalid HTTP response code: " . $response->code . "\n";
181             }
182              
183 1 50       12 if ( $response->content =~ /accounts\[count\] = "\s*(\d+)\s*"/ ) {
184 1         15 $self->{acct_no} = $1;
185 1         3 chomp $self->{acct_no};
186             #warn "Account number: --" . $self->{acct_no} . "--\n";
187             }
188             else {
189 0         0 die "Parse error while getting account number\n";
190             }
191              
192 1 50       4 if ( $response->content =~ /balance\[count\] = "(.*)"/ ) {
193 1         14 return $1;
194             }
195             else {
196 0         0 die "Parse error while getting account balance\n";
197             }
198              
199              
200             }
201              
202             ### INSTANCE METHOD ##################################################
203             # Usage : @statements = $obj->get_mini_statement()
204             # Purpose : Get account mini statement
205             # Returns :
206             # : 1) @statements => array of hashrefs
207             # Parameters : None
208             # Throws :
209             # : * "Not logged in\n"
210             # : * "HTTP error while getting account balance\n"
211             # : * "Got an invalid HTTP response code: $code\n"
212             # : * "Parse error while getting mini statement\n"
213             # Comments :
214             # : * Does not support multiple accounts
215             # See Also : n/a
216             #######################################################################
217             sub get_mini_statement {
218 1     1 0 510 my ($self) = @_;
219              
220             # Check that user has logged in
221 1 50       9 if ( $self->{'session_id'} eq q{} ) {
222 0         0 die "Not logged in\n";
223             }
224              
225             # and that we have her account number
226 1 50       5 if ($self->{acct_no} eq q{}) {
227 0         0 $self->get_balance();
228             }
229              
230             # Get the account balance
231 1         5 my $transaction_id = $TRANSACTION_CODES{'mini_statement'};
232              
233 1         16 $self->{'request'}->content( "fldSessionId="
234             . $self->{'session_id'} . '&'
235             . "fldAppId=RS" . '&'
236             . "fldTxnId=$transaction_id" . '&'
237             . "fldNbrStmt=20" . '&'
238             . "fldTxnType=A" . '&'
239             . "radTxnType=C" . '&'
240             . "fldScrnSeqNbr=02" . '&'
241             . "fldAcctNo=" . $self->{acct_no} . '&'
242             . "fldModule=CH" );
243              
244 1         17 my $response = $self->{'ua'}->request( $self->{'request'} );
245              
246 1 50       68 if ( $response->is_error ) {
247 0         0 die "HTTP error while getting mini statement\n";
248             }
249              
250 1 50       26 if ( $response->code != 200 ) {
251 0         0 die "Got invalid HTTP response code: " . $response->code . "\n";
252             }
253              
254             #die $template_mini_statement;
255             #die $response->content;
256 1         17 my $template = Template::Extract->new;
257 1         54385 my $ref = $template->extract($TEMPLATE_MINI_STATEMENT, $response->content);
258             #warn Dumper $ref;
259              
260 1         9910 return @{$ref->{record}};
  1         55  
261             }
262              
263             ### INSTANCE METHOD ###################################################
264             # Usage : $obj->logout()
265             # Purpose : Logout from the netbanking system
266             # Returns : 1 on success
267             # Parameters : None
268             # Throws :
269             # : * "Not logged in\n"
270             # : * "HTTP error while logging out\n"
271             # : * "Got an invalid HTTP response code: $code\n"
272             # Comments : none
273             # See Also : n/a
274             #######################################################################
275             sub logout {
276 1     1 0 1774 my ($self) = @_;
277              
278             # Check that user has logged in
279 1 50       7 if ( $self->{'session_id'} eq q{} ) {
280 0         0 die "Not logged in\n";
281             }
282              
283 1         12 my $transaction_id = $TRANSACTION_CODES{'logout'};
284              
285 1         20 $self->{'request'}->content( "fldSessionId="
286             . $self->{'session_id'} . '&'
287             . "fldAppId=RS" . '&'
288             . "fldTxnId=$transaction_id" . '&'
289             . "fldScrnSeqNbr=01" . '&'
290             . "fldModule=CH" );
291              
292             # Logout
293 1         32 my $response = $self->{'ua'}->request( $self->{'request'} );
294              
295 1 50       84 if ( $response->is_error ) {
296 0         0 die "HTTP error while logging out\n";
297             }
298              
299 1 50       13 if ( $response->code != 200 ) {
300 0         0 die "Got invalid HTTP response code: " . $response->code . "\n";
301             }
302              
303 1         12 return 1;
304             }
305              
306             ### INSTANCE METHOD ###################################################
307             # Usage : $bank->set_timeout($timeout)
308             # Purpose : Set HTTP timeout for LWP::UserAgent
309             # Returns : The timeout set
310             # Parameters :
311             # : 1) $timeout => HTTP timeout in seconds
312             # Throws : no exceptions
313             # Comments : none
314             # See Also : n/a
315             #######################################################################
316             sub set_timeout {
317 1     1 0 543 my ( $self, $timeout ) = @_;
318              
319 1         13 $self->{'ua'}->timeout($timeout);
320 1         19 return $self->{'ua'}->timeout();
321             }
322              
323             1;
324              
325             __END__