File Coverage

blib/lib/Finance/OFX.pm
Criterion Covered Total %
statement 12 75 16.0
branch 0 44 0.0
condition 0 3 0.0
subroutine 4 14 28.5
pod 8 10 80.0
total 24 146 16.4


line stmt bran cond sub pod time code
1             # Filename: OFX.pm
2             # Serialize, Parse and Query using the Open Financial Exchange format
3             # http://www.ofx.net/
4             #
5             # Created January 30, 2008 Brandon Fosdick
6             #
7             # Copyright 2008 Brandon Fosdick (BSD License)
8             #
9             # $Id: OFX.pm,v 1.2 2008/03/04 04:22:24 bfoz Exp $
10              
11             package Finance::OFX;
12              
13 1     1   30118 use strict;
  1         3  
  1         45  
14 1     1   7 use warnings;
  1         1  
  1         49  
15              
16             our $VERSION = '2';
17              
18 1     1   815 use Finance::OFX::UserAgent;
  1         3  
  1         34  
19              
20 1     1   7 use HTTP::Date;
  1         3  
  1         6901  
21              
22             sub new
23             {
24 0     0 1   my ($this, %options) = @_;
25 0   0       my $class = ref($this) || $this;
26 0           my $self = {};
27 0           bless $self, $class;
28              
29             # Assume any unprocessed options are meant for the UserAgent,
30             # which implies that this object will be used to generate and process
31             # requests instead of processing stored files
32 0 0         $self->{ua} = Finance::OFX::UserAgent->new(%options) if scalar keys %options;
33              
34 0           return $self;
35             }
36              
37             # --- Getters and Setters ---
38              
39             sub institution
40             {
41 0     0 1   my $s = shift;
42 0           $s->{ua}->institution(@_);
43             }
44              
45             sub response
46             {
47 0     0 1   my $s = shift;
48 0           $s->{ua}->{response};
49             }
50              
51             sub user_id
52             {
53 0     0 1   my $s = shift;
54 0           $s->{ua}->user_id(@_);
55             }
56              
57             sub user_pass
58             {
59 0     0 1   my $s = shift;
60 0           $s->{ua}->user_pass(@_);
61             }
62              
63             # --- Public Methods ---
64              
65             sub accounts
66             {
67 0     0 1   my $s = shift;
68              
69 0           my $r = $s->{ua}->account_info;
70              
71 0 0         return -1 unless $r->is_success;
72 0 0         return -2 if $r->signon_status_code;
73 0 0         return undef unless $r->ofx->{signupmsgsrsv1}{acctinfotrnrs}{acctinfors}{acctinfo};
74              
75 0           my @accounts;
76 0           for( @{$r->ofx->{signupmsgsrsv1}{acctinfotrnrs}{acctinfors}{acctinfo}} )
  0            
77             {
78 0           my %b = flatten($_);
79 0           push @accounts, \%b;
80             }
81 0           return @accounts;
82             }
83              
84             sub balance
85             {
86 0     0 1   my ($s, $acct) = @_;
87 0 0         return undef unless ref($acct) eq 'Finance::OFX::Account';
88              
89             # Use the FID from the given FI if none is set in the given Account
90 0 0         $acct->fid($s->institution()->fid()) unless $acct->fid();
91              
92 0           my $r = $s->{ua}->statement($acct);
93 0 0         return -1 unless $r->is_success;
94 0 0         return -2 if $r->signon_status_code;
95 0 0         return undef unless $r->ofx->{bankmsgsrsv1}{stmttrnrs};
96              
97 0           my $transaction = $r->ofx->{bankmsgsrsv1}{stmttrnrs};
98 0 0         return "Statement request error: ".($transaction->{status}{message}) if transactionStatusCode($transaction);
99 0 0         return "No statement info returned" unless exists $transaction->{stmtrs};
100              
101 0           return $transaction->{stmtrs};
102             }
103              
104             sub transactions
105             {
106 0     0 1   my ($s, $acct, $start, $end) = @_;
107 0 0         return undef unless ref($acct) eq 'Finance::OFX::Account';
108              
109             # Use the FID from the given FI if none is set in the given Account
110 0 0         $acct->fid($s->institution()->fid()) unless $acct->fid();
111              
112 0           my %options;
113 0           $options{transactions} = 'Y';
114 0 0         $options{start} = $start if $start;
115 0 0         $options{end} = $end if $end;
116              
117 0           my $r = $s->{ua}->statement($acct, %options);
118 0 0         return -1 unless $r->is_success;
119 0 0         return -2 if $r->signon_status_code;
120 0           my $ofx = $r->ofx;
121 0 0         return undef unless $ofx->{bankmsgsrsv1}{stmttrnrs}{stmtrs};
122 0           my $transaction = $ofx->{bankmsgsrsv1}{stmttrnrs};
123 0 0         return "Statement request error: ".($transaction->{status}{message}) if transactionStatusCode($transaction);
124              
125 0           return $transaction->{stmtrs}{banktranlist};
126             }
127              
128             sub transactionStatusCode
129             {
130 0     0 0   my $tree = shift;
131 0 0         return undef unless ref($tree) eq 'HASH';
132 0           return $tree->{status}{code};
133             }
134              
135             # --- Internal use only ---
136              
137             # Blindly flatten a HoH
138             sub flatten
139             {
140 0     0 0   my $tree = shift;
141 0 0         return $tree unless ref($tree) eq 'HASH';
142 0           my %a;
143 0           for( keys %{$tree} )
  0            
144             {
145 0 0         $a{$_} = $tree->{$_}, next unless ref($tree->{$_}) eq 'HASH';
146 0           my %b = flatten($tree->{$_});
147 0           @a{keys %b} = values %b;
148             }
149 0           return %a;
150             }
151              
152             1;
153              
154             __END__