ofx_for_ruby 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (74) hide show
  1. data/.externalToolBuilders/Rebuild parsers.launch +10 -0
  2. data/.gitignore +9 -0
  3. data/.loadpath +5 -0
  4. data/.project +27 -0
  5. data/COPYING +674 -0
  6. data/Gemfile +2 -0
  7. data/README +47 -0
  8. data/RELEASE_NOTES +45 -0
  9. data/Rakefile +63 -0
  10. data/lib/ofx.rb +60 -0
  11. data/lib/ofx/1.0.2/banking_message_set.rb +261 -0
  12. data/lib/ofx/1.0.2/credit_card_statement_message_set.rb +269 -0
  13. data/lib/ofx/1.0.2/document.rb +34 -0
  14. data/lib/ofx/1.0.2/email_message_set.rb +34 -0
  15. data/lib/ofx/1.0.2/financial_institution_profile_message_set.rb +155 -0
  16. data/lib/ofx/1.0.2/header.rb +48 -0
  17. data/lib/ofx/1.0.2/interbank_funds_transfer_message_set.rb +30 -0
  18. data/lib/ofx/1.0.2/investment_security_list_message_set.rb +30 -0
  19. data/lib/ofx/1.0.2/investment_statement_message_set.rb +30 -0
  20. data/lib/ofx/1.0.2/lexer.rb +135 -0
  21. data/lib/ofx/1.0.2/message_set.rb +165 -0
  22. data/lib/ofx/1.0.2/ofx_102.racc +90 -0
  23. data/lib/ofx/1.0.2/ofx_102.rex +65 -0
  24. data/lib/ofx/1.0.2/parser.rb +215 -0
  25. data/lib/ofx/1.0.2/payment_message_set.rb +30 -0
  26. data/lib/ofx/1.0.2/serializer.rb +114 -0
  27. data/lib/ofx/1.0.2/signon_message_set.rb +121 -0
  28. data/lib/ofx/1.0.2/signup_message_set.rb +186 -0
  29. data/lib/ofx/1.0.2/statements.rb +54 -0
  30. data/lib/ofx/1.0.2/status.rb +30 -0
  31. data/lib/ofx/1.0.2/wire_funds_transfer_message_set.rb +30 -0
  32. data/lib/ofx/banking_message_set.rb +125 -0
  33. data/lib/ofx/credit_card_statement_message_set.rb +104 -0
  34. data/lib/ofx/document.rb +30 -0
  35. data/lib/ofx/email_message_set.rb +42 -0
  36. data/lib/ofx/file_unique_identifier.rb +28 -0
  37. data/lib/ofx/financial_client.rb +76 -0
  38. data/lib/ofx/financial_institution.rb +83 -0
  39. data/lib/ofx/financial_institution_profile_message_set.rb +67 -0
  40. data/lib/ofx/header.rb +115 -0
  41. data/lib/ofx/http/cacert.pem +3509 -0
  42. data/lib/ofx/http/ofx_http_client.rb +84 -0
  43. data/lib/ofx/interbank_funds_transfer_message_set.rb +33 -0
  44. data/lib/ofx/investment_security_list_message_set.rb +33 -0
  45. data/lib/ofx/investment_statement_message_set.rb +33 -0
  46. data/lib/ofx/message_set.rb +78 -0
  47. data/lib/ofx/payment_message_set.rb +33 -0
  48. data/lib/ofx/serializer.rb +39 -0
  49. data/lib/ofx/signon_message_set.rb +141 -0
  50. data/lib/ofx/signup_message_set.rb +84 -0
  51. data/lib/ofx/statements.rb +49 -0
  52. data/lib/ofx/status.rb +100 -0
  53. data/lib/ofx/transaction_unique_identifier.rb +28 -0
  54. data/lib/ofx/version.rb +82 -0
  55. data/lib/ofx/wire_funds_transfer_message_set.rb +33 -0
  56. data/ofx_for_ruby.gemspec +25 -0
  57. data/planning/OFX Specification completion.ods +0 -0
  58. data/test/capital_one/capital_one_helper.rb +77 -0
  59. data/test/capital_one/fixtures/README +10 -0
  60. data/test/capital_one/fixtures/fipid-5599.xml +98 -0
  61. data/test/capital_one/test_banking_statement.rb +108 -0
  62. data/test/capital_one/test_financial_institution_profile.rb +295 -0
  63. data/test/capital_one/test_ofx_http_client.rb +72 -0
  64. data/test/capital_one/test_signup_account_information.rb +100 -0
  65. data/test/citi/citi_helper.rb +77 -0
  66. data/test/citi/fixtures/README +9 -0
  67. data/test/citi/fixtures/fipid-6642.xml +98 -0
  68. data/test/citi/test_credit_card_statement.rb +159 -0
  69. data/test/citi/test_financial_institution_profile.rb +231 -0
  70. data/test/citi/test_ofx_http_client.rb +71 -0
  71. data/test/citi/test_signup_account_information.rb +85 -0
  72. data/test/test_helper.rb +4 -0
  73. data/test/test_ofx_version.rb +141 -0
  74. metadata +210 -0
@@ -0,0 +1,65 @@
1
+ # Copyright © 2007 Chris Guidry <chrisguidry@gmail.com>
2
+ #
3
+ # This file is part of OFX for Ruby.
4
+ #
5
+ # OFX for Ruby is free software; you can redistribute it and/or modify
6
+ # it under the terms of the GNU General Public License as published by
7
+ # the Free Software Foundation; either version 3 of the License, or
8
+ # (at your option) any later version.
9
+ #
10
+ # OFX for Ruby is distributed in the hope that it will be useful,
11
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+ # GNU General Public License for more details.
14
+ #
15
+ # You should have received a copy of the GNU General Public License
16
+ # along with this program. If not, see <http://www.gnu.org/licenses/>.
17
+
18
+ module OFX
19
+ module OFX102
20
+ class Parser
21
+ option
22
+
23
+ macro
24
+ TAG_IN \<
25
+ TAG_OUT \>
26
+ ETAG_IN \<\/
27
+
28
+ rule
29
+
30
+ # [:state] pattern [actions]
31
+ {ETAG_IN} { state = :TAG; [:etag_in, text] }
32
+ {TAG_IN} { state = :TAG; [:tag_in, text] }
33
+
34
+ :TAG {TAG_OUT} { state = nil; [:tag_out, text] }
35
+
36
+ :TAG [\w\-\.]+ { [:element, text] }
37
+
38
+
39
+ \s+(?=\S)
40
+ .*?(?=({TAG_IN}|{ETAG_IN})+?) { [:text, text] }
41
+ .*\S(?=\s*$) { [:text, text] }
42
+ \s+(?=$)
43
+
44
+ inner
45
+
46
+ end
47
+
48
+ end # module OFX102
49
+ end # module OFX
50
+
51
+ =begin
52
+ if __FILE__ == $0
53
+ exit if ARGV.size != 1
54
+ filename = ARGV.shift
55
+ rex = OFX::OFX102::Parser.new
56
+ begin
57
+ rex.load_file filename
58
+ while token = rex.next_token
59
+ p token
60
+ end
61
+ rescue
62
+ $stderr.printf "%s:%d:%s\n", rex.filename, rex.lineno, $!.message
63
+ end
64
+ end
65
+ =end
@@ -0,0 +1,215 @@
1
+ #
2
+ # DO NOT MODIFY!!!!
3
+ # This file is automatically generated by Racc 1.4.6
4
+ # from Racc grammer file "".
5
+ #
6
+
7
+ require 'racc/parser.rb'
8
+
9
+ #
10
+ # generated by racc
11
+ #
12
+ require File.dirname(__FILE__) + '/lexer'
13
+
14
+ module OFX
15
+ module OFX102
16
+ class Parser < Racc::Parser
17
+
18
+ module_eval(<<'...end ofx_102.racc/module_eval...', 'ofx_102.racc', 48)
19
+
20
+ attr :documents
21
+ attr :ofx_hashes
22
+
23
+ def initialize
24
+ @documents = []
25
+ @ofx_hashes = []
26
+
27
+ @tags_stack = []
28
+ end
29
+
30
+ private
31
+ def start_tag(tag_name)
32
+ # push an empty aggregate/value tag
33
+ @tags_stack.push({ tag_name => {} })
34
+ end
35
+
36
+ def data_value(value)
37
+ # pop the most recent tag, and use it's name as the key in the next higher tag's hash
38
+ tag = @tags_stack.pop
39
+ @tags_stack.last[@tags_stack.last.keys[0]][tag.keys[0]] = CGI::unescapeHTML(value)
40
+ end
41
+
42
+ def end_tag(tag_name)
43
+ # pop the most recent tag, stop and recognize this as a full document if this is the last tag; otherwise,
44
+ # use this tag's naem as the key in the next higher tag's hash
45
+ tag = @tags_stack.pop
46
+ if (@tags_stack.empty?)
47
+ @ofx_hashes << tag
48
+ @documents << OFX::Document.from_ofx_102_hash(tag)
49
+ else
50
+ previous = @tags_stack.last[@tags_stack.last.keys[0]][tag.keys[0]]
51
+ if previous == nil
52
+ @tags_stack.last[@tags_stack.last.keys[0]][tag.keys[0]] = tag[tag.keys[0]]
53
+ elsif previous.kind_of?(Array)
54
+ previous << tag[tag.keys[0]]
55
+ else
56
+ @tags_stack.last[@tags_stack.last.keys[0]][tag.keys[0]] = [previous, tag[tag.keys[0]]]
57
+ end
58
+ end
59
+ end
60
+
61
+ ...end ofx_102.racc/module_eval...
62
+ ##### State transition tables begin ###
63
+
64
+ racc_action_table = [
65
+ 1, 6, 1, 14, 15, 14, 15, 8, 9, 5,
66
+ 17, 19, 20, 1 ]
67
+
68
+ racc_action_check = [
69
+ 18, 2, 7, 18, 18, 7, 7, 5, 6, 1,
70
+ 14, 16, 17, 0 ]
71
+
72
+ racc_action_pointer = [
73
+ 11, 6, 1, nil, nil, 3, 8, 0, nil, nil,
74
+ nil, nil, nil, nil, 7, nil, 5, 8, -2, nil,
75
+ nil, nil ]
76
+
77
+ racc_action_default = [
78
+ -1, -13, -13, -2, -6, -13, -13, -13, -4, 22,
79
+ -3, -7, -9, -10, -13, -8, -6, -13, -13, -12,
80
+ -5, -11 ]
81
+
82
+ racc_goto_table = [
83
+ 7, 4, 10, 3, 2, nil, nil, nil, nil, nil,
84
+ nil, nil, 18, 21 ]
85
+
86
+ racc_goto_check = [
87
+ 4, 3, 5, 2, 1, nil, nil, nil, nil, nil,
88
+ nil, nil, 4, 5 ]
89
+
90
+ racc_goto_pointer = [
91
+ nil, 4, 3, 1, -4, -5, nil, nil, nil ]
92
+
93
+ racc_goto_default = [
94
+ nil, nil, nil, 16, nil, nil, 11, 12, 13 ]
95
+
96
+ racc_reduce_table = [
97
+ 0, 0, :racc_error,
98
+ 0, 8, :_reduce_none,
99
+ 1, 8, :_reduce_none,
100
+ 3, 9, :_reduce_none,
101
+ 3, 10, :_reduce_4,
102
+ 3, 12, :_reduce_5,
103
+ 0, 11, :_reduce_none,
104
+ 2, 11, :_reduce_none,
105
+ 1, 13, :_reduce_none,
106
+ 1, 13, :_reduce_none,
107
+ 1, 13, :_reduce_none,
108
+ 3, 14, :_reduce_none,
109
+ 2, 15, :_reduce_12 ]
110
+
111
+ racc_reduce_n = 13
112
+
113
+ racc_shift_n = 22
114
+
115
+ racc_token_table = {
116
+ false => 0,
117
+ :error => 1,
118
+ :tag_in => 2,
119
+ :element => 3,
120
+ :tag_out => 4,
121
+ :etag_in => 5,
122
+ :text => 6 }
123
+
124
+ racc_nt_base = 7
125
+
126
+ racc_use_result_var = true
127
+
128
+ Racc_arg = [
129
+ racc_action_table,
130
+ racc_action_check,
131
+ racc_action_default,
132
+ racc_action_pointer,
133
+ racc_goto_table,
134
+ racc_goto_check,
135
+ racc_goto_default,
136
+ racc_goto_pointer,
137
+ racc_nt_base,
138
+ racc_reduce_table,
139
+ racc_token_table,
140
+ racc_shift_n,
141
+ racc_reduce_n,
142
+ racc_use_result_var ]
143
+
144
+ Racc_token_to_s_table = [
145
+ "$end",
146
+ "error",
147
+ "tag_in",
148
+ "element",
149
+ "tag_out",
150
+ "etag_in",
151
+ "text",
152
+ "$start",
153
+ "target",
154
+ "ofx_body",
155
+ "tag_from",
156
+ "contents",
157
+ "tag_to",
158
+ "content",
159
+ "aggregate",
160
+ "value" ]
161
+
162
+ Racc_debug_parser = false
163
+
164
+ ##### State transition tables end #####
165
+
166
+ # reduce 0 omitted
167
+
168
+ # reduce 1 omitted
169
+
170
+ # reduce 2 omitted
171
+
172
+ # reduce 3 omitted
173
+
174
+ module_eval(<<'.,.,', 'ofx_102.racc', 25)
175
+ def _reduce_4(val, _values, result)
176
+ start_tag(val[1])
177
+ result
178
+ end
179
+ .,.,
180
+
181
+ module_eval(<<'.,.,', 'ofx_102.racc', 26)
182
+ def _reduce_5(val, _values, result)
183
+ end_tag(val[1])
184
+ result
185
+ end
186
+ .,.,
187
+
188
+ # reduce 6 omitted
189
+
190
+ # reduce 7 omitted
191
+
192
+ # reduce 8 omitted
193
+
194
+ # reduce 9 omitted
195
+
196
+ # reduce 10 omitted
197
+
198
+ # reduce 11 omitted
199
+
200
+ module_eval(<<'.,.,', 'ofx_102.racc', 36)
201
+ def _reduce_12(val, _values, result)
202
+ data_value(val[1])
203
+ result
204
+ end
205
+ .,.,
206
+
207
+ def _reduce_none(val, _values, result)
208
+ val[0]
209
+ end
210
+
211
+ end # class Parser
212
+ end # module OFX102
213
+ end # module OFX
214
+
215
+
@@ -0,0 +1,30 @@
1
+ # Copyright © 2007 Chris Guidry <chrisguidry@gmail.com>
2
+ #
3
+ # This file is part of OFX for Ruby.
4
+ #
5
+ # OFX for Ruby is free software; you can redistribute it and/or modify
6
+ # it under the terms of the GNU General Public License as published by
7
+ # the Free Software Foundation; either version 3 of the License, or
8
+ # (at your option) any later version.
9
+ #
10
+ # OFX for Ruby is distributed in the hope that it will be useful,
11
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+ # GNU General Public License for more details.
14
+ #
15
+ # You should have received a copy of the GNU General Public License
16
+ # along with this program. If not, see <http://www.gnu.org/licenses/>.
17
+
18
+ module OFX
19
+ class PaymentMessageSet < MessageSet
20
+ end
21
+
22
+ class PaymentMessageSetProfile < MessageSetProfile
23
+ def self.from_ofx_102_hash(message_set_description_hash)
24
+ profile = OFX::PaymentMessageSetProfile.new
25
+ profile.message_set_class = OFX::PaymentMessageSet
26
+ profile.from_ofx_102_hash(message_set_description_hash)
27
+ profile
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,114 @@
1
+ # Copyright © 2007 Chris Guidry <chrisguidry@gmail.com>
2
+ #
3
+ # This file is part of OFX for Ruby.
4
+ #
5
+ # OFX for Ruby is free software; you can redistribute it and/or modify
6
+ # it under the terms of the GNU General Public License as published by
7
+ # the Free Software Foundation; either version 3 of the License, or
8
+ # (at your option) any later version.
9
+ #
10
+ # OFX for Ruby is distributed in the hope that it will be useful,
11
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+ # GNU General Public License for more details.
14
+ #
15
+ # You should have received a copy of the GNU General Public License
16
+ # along with this program. If not, see <http://www.gnu.org/licenses/>.
17
+
18
+ require File.dirname(__FILE__) + '/document'
19
+ require File.dirname(__FILE__) + '/header'
20
+ require File.dirname(__FILE__) + '/message_set'
21
+ require File.dirname(__FILE__) + '/status'
22
+ require File.dirname(__FILE__) + '/statements'
23
+
24
+ require File.dirname(__FILE__) + '/signon_message_set'
25
+ require File.dirname(__FILE__) + '/signup_message_set'
26
+ require File.dirname(__FILE__) + '/banking_message_set'
27
+ require File.dirname(__FILE__) + '/credit_card_statement_message_set'
28
+ require File.dirname(__FILE__) + '/investment_statement_message_set'
29
+ require File.dirname(__FILE__) + '/interbank_funds_transfer_message_set'
30
+ require File.dirname(__FILE__) + '/wire_funds_transfer_message_set'
31
+ require File.dirname(__FILE__) + '/payment_message_set'
32
+ require File.dirname(__FILE__) + '/email_message_set'
33
+ require File.dirname(__FILE__) + '/investment_security_list_message_set'
34
+ require File.dirname(__FILE__) + '/financial_institution_profile_message_set'
35
+
36
+ require File.dirname(__FILE__) + '/parser'
37
+
38
+ module OFX
39
+ module OFX102
40
+ class Serializer
41
+ def to_http_post_body(document)
42
+ body = ""
43
+
44
+ body += document.header.to_ofx_102_s
45
+ body += "\n"
46
+ body += "<OFX>\n"
47
+ document.message_sets.each do |message_set|
48
+ body += message_set.to_ofx_102_s
49
+ end
50
+ body += "</OFX>\n"
51
+
52
+ #print body
53
+
54
+ body
55
+ end
56
+
57
+ def from_http_response_body(body)
58
+ header_pattern = /(\w+\:.*\n)+/
59
+ header_match = header_pattern.match(body)
60
+
61
+ body = header_match.post_match
62
+ header = Header.from_ofx_102_s(header_match[0].strip)
63
+
64
+ parser = OFX::OFX102::Parser.new
65
+ parser.scan_str body
66
+
67
+ if parser.documents.length > 1
68
+ raise NotImplementedError, "Multiple response documents"
69
+ end
70
+
71
+ #require 'pp'
72
+ #print body
73
+ #pp parser.ofx_hashes[0]
74
+
75
+ document = parser.documents[0]
76
+ document.header = header
77
+ document
78
+ end
79
+ end
80
+ end
81
+ end
82
+
83
+ require 'date'
84
+ class Date
85
+ def to_ofx_102_s
86
+ strftime('%Y%m%d')
87
+ end
88
+ end
89
+ class DateTime
90
+ def to_ofx_102_s
91
+ strftime('%Y%m%d%H%M%S')
92
+ end
93
+ end
94
+ class String
95
+ def to_date
96
+ Date.parse(self)
97
+ end
98
+ def to_datetime
99
+ DateTime.parse(self)
100
+ end
101
+ def to_time
102
+ ('-47120101' + self).to_datetime
103
+ end
104
+ end
105
+ class TrueClass
106
+ def to_ofx_102_s
107
+ 'Y'
108
+ end
109
+ end
110
+ class FalseClass
111
+ def to_ofx_102_s
112
+ 'Y'
113
+ end
114
+ end
@@ -0,0 +1,121 @@
1
+ # Copyright © 2007 Chris Guidry <chrisguidry@gmail.com>
2
+ #
3
+ # This file is part of OFX for Ruby.
4
+ #
5
+ # OFX for Ruby is free software; you can redistribute it and/or modify
6
+ # it under the terms of the GNU General Public License as published by
7
+ # the Free Software Foundation; either version 3 of the License, or
8
+ # (at your option) any later version.
9
+ #
10
+ # OFX for Ruby is distributed in the hope that it will be useful,
11
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+ # GNU General Public License for more details.
14
+ #
15
+ # You should have received a copy of the GNU General Public License
16
+ # along with this program. If not, see <http://www.gnu.org/licenses/>.
17
+
18
+ module OFX
19
+ class SignonMessageSet < MessageSet
20
+ def ofx_102_message_set_name
21
+ 'SIGNON'
22
+ end
23
+
24
+ def self.from_ofx_102_hash(message_set_hash)
25
+ message_set = SignonMessageSet.new
26
+
27
+ message_set_hash.each_pair() do |response_or_request_name, response_or_request_hash|
28
+ case response_or_request_name
29
+ when "SONRQ" then message_set.requests << SignonRequest.from_ofx_102_hash(response_or_request_hash)
30
+ when "SONRS" then message_set.responses << SignonResponse.from_ofx_102_hash(response_or_request_hash)
31
+ else raise NotImplementedError, response_or_request_name
32
+ end
33
+ end
34
+
35
+ return message_set
36
+ end
37
+ end
38
+
39
+ class SignonMessageSetProfile < MessageSetProfile
40
+ def self.from_ofx_102_hash(message_set_description_hash)
41
+ profile = OFX::SignonMessageSetProfile.new
42
+ profile.message_set_class = OFX::SignonMessageSet
43
+ profile.from_ofx_102_hash(message_set_description_hash)
44
+ profile
45
+ end
46
+ end
47
+
48
+ class SignonRequest < Request
49
+ def ofx_102_name
50
+ 'SON'
51
+ end
52
+ def ofx_102_request_body
53
+ " <DTCLIENT>#{date.to_ofx_102_s}\n" +
54
+ user_identification.to_ofx_102_s + "\n" +
55
+ (" <GENUSERKEY>#{generate_user_key}\n" if generate_user_key).to_s +
56
+ " <LANGUAGE>#{language}\n" +
57
+ financial_institution_identification.to_ofx_102_s + "\n" +
58
+ (" <SESSCOOKIE>#{session_cookie}\n" if session_cookie).to_s +
59
+ application_identification.to_ofx_102_s
60
+ end
61
+ def self.from_ofx_102_hash(request_hash)
62
+ raise NotImplementedError
63
+ end
64
+ end
65
+ class UserCredentials
66
+ def to_ofx_102_s
67
+ " <USERID>#{user_identification}\n" +
68
+ " <USERPASS>#{password}"
69
+ end
70
+ end
71
+ class UserKey
72
+ def to_ofx_102_s
73
+ " <USERKEY>#{user_key}"
74
+ end
75
+ end
76
+
77
+ class FinancialInstitutionIdentification
78
+ def to_ofx_102_s
79
+ " <FI>\n" +
80
+ " <ORG>#{organization}\n" +
81
+ " <FID>#{financial_institution_identifier}\n" +
82
+ " </FI>"
83
+ end
84
+ def self.from_ofx_102_hash(fi_hash)
85
+ return FinancialInstitutionIdentification.new(fi_hash['ORG'],
86
+ fi_hash['FID'])
87
+ end
88
+ end
89
+
90
+ class ApplicationIdentification
91
+ def to_ofx_102_s
92
+ " <APPID>#{application_identification}\n" +
93
+ " <APPVER>#{application_version}"
94
+ end
95
+ end
96
+
97
+ class SignonResponse < Response
98
+ def ofx_102_name
99
+ 'SON'
100
+ end
101
+
102
+ def ofx_102_response_body
103
+ raise NotImplementedError
104
+ end
105
+
106
+ def self.from_ofx_102_hash(response_hash)
107
+ response = SignonResponse.new
108
+
109
+ response.status = OFX::Status.from_ofx_102_hash(response_hash['STATUS'])
110
+ response.date = response_hash['DTSERVER'].to_datetime if response_hash['DTSERVER']
111
+ #TODO: @user_key
112
+ response.language = response_hash['LANGUAGE']
113
+ response.date_of_last_profile_update = response_hash['DTPROFUP'].to_datetime if response_hash['DTPROFUP']
114
+ response.date_of_last_account_update = response_hash['DTACCTUP'].to_datetime if response_hash['DTACCTUP']
115
+ response.financial_institution_identification = OFX::FinancialInstitutionIdentification.from_ofx_102_hash(response_hash['FI'])
116
+ #TODO: @session_cookie
117
+
118
+ response
119
+ end
120
+ end
121
+ end