ofx_for_ruby 0.1.3 → 0.1.5

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 430b7f5c78f4a4dc08653128f5ec829d34e89079
4
- data.tar.gz: 7a6a023f4882b3f1f04a1e5e8f7d0693f316cdf5
3
+ metadata.gz: 41a866d8860d900a7fee63c524916d3d9cc0f771
4
+ data.tar.gz: 59869261ce4b873f2b10e63502e5d36ad45ba0c0
5
5
  SHA512:
6
- metadata.gz: cb65456b98851a449e4f2124a461c0c650252565dff75d17cd8e8e0218e2a5f7f35401f437d4d8667f5ba711da233f58487f59b0aa0ace963e0b09722ab527a7
7
- data.tar.gz: 980c88061fa30811e7a1e0c43cd350d4a964498e95d4b3df8b1d818359076e6e70ccec35b26f10261aa9c0fb55abd4d04e7d26eee268874d8c8db9f29042a317
6
+ metadata.gz: fa7e804432236f4d49c66899a47abe5091a6845beb0898e7419334d67605828bd18f7b9db87f064cbc7ff5ba044647c53ec8467662539a2e68025eb0d72c2416
7
+ data.tar.gz: 757f22807ba8f6e6924360fa1dd4a607972d5fc201c691d3b505ad8b063d1923be03b21cf4a143e4e514f2c051453696d1f70d4a2b26324f1950ecb737d22054
data/.gitignore CHANGED
@@ -7,3 +7,4 @@ test/capital_one/fixtures/capital-one-credentials
7
7
  pkg
8
8
  coverage
9
9
  documentation
10
+ tmp
data/README CHANGED
@@ -1,4 +1,4 @@
1
- This is a fork of the "OFX for Ruby" project developed by Chris Guidry <chrisguidry@gmail.com> and hosted on Rubyforge: http://rubyforge.org/projects/ofxget/. That repository has not been updated since early 2008.
1
+ This is a fork of the "OFX for Ruby" project developed by Chris Guidry <chrisguidry@gmail.com> and hosted on Rubyforge: http://rubyforge.org/projects/ofx/. That repository has not been updated since early 2008.
2
2
 
3
3
  ---------------------------------------
4
4
 
data/USAGE ADDED
@@ -0,0 +1,17 @@
1
+
2
+ An easy way to pull your OFX data is with:
3
+
4
+ fi = OFX::FinancialInstitution.get_institution('Chase')
5
+ fi.set_client(<user>, <pass>)
6
+ id = fi.get_account_id
7
+ resp = fi.send(fi.create_request_document_for_cc_statement(id))
8
+
9
+
10
+ If making changes, please test the following to ensure no regressions.
11
+ That is, the following should return data and no HTTP errors.
12
+
13
+ OFX::FinancialInstitution.get_institution('Capital One').get_anon_profile
14
+ OFX::FinancialInstitution.get_institution('Citi').get_anon_profile
15
+ OFX::FinancialInstitution.get_institution('Chase').get_anon_profile
16
+ OFX::FinancialInstitution.get_institution('AMEX').get_anon_profile
17
+
@@ -206,7 +206,9 @@ module OFX
206
206
 
207
207
  transaction_list_hash = response_hash['BANKTRANLIST']
208
208
  if (transaction_list_hash)
209
- response.transaction_range = transaction_list_hash['DTSTART'].to_datetime..transaction_list_hash['DTEND'].to_datetime
209
+ if transaction_list_hash['DTSTART'] && transaction_list_hash['DTEND']
210
+ response.transaction_range = transaction_list_hash['DTSTART'].to_datetime..transaction_list_hash['DTEND'].to_datetime
211
+ end
210
212
 
211
213
  response.transactions = []
212
214
  transactions = transaction_list_hash['STMTTRN'] if transaction_list_hash['STMTTRN'].kind_of?(Array)
@@ -221,7 +223,7 @@ module OFX
221
223
  transaction.date_initiated = transaction_hash['DTUSER'].to_datetime if transaction_hash['DTUSER']
222
224
  transaction.date_available = transaction_hash['DTAVAIL'].to_datetime if transaction_hash['DTAVAIL']
223
225
 
224
- transaction.amount = transaction_hash['TRNAMT'].to_d
226
+ transaction.amount = transaction_hash['TRNAMT'].to_d if transaction_hash['TRNAMT']
225
227
  transaction.currency = transaction_hash['CURRENCY'] || transaction_hash['ORIGCURRENCY'] || response.default_currency
226
228
 
227
229
  transaction.financial_institution_transaction_identifier = transaction_hash['FITID']
@@ -258,4 +260,4 @@ module OFX
258
260
  response
259
261
  end
260
262
  end
261
- end
263
+ end
@@ -84,22 +84,19 @@ module OFX
84
84
  def ofx_102_name
85
85
  'CCSTMT'
86
86
  end
87
+
87
88
  def ofx_102_request_body
88
89
  body = ""
89
-
90
90
  body += account.to_ofx_102_request_body
91
-
92
91
  body +=
93
- " <INCTRAN>\n" +
94
- " <INCLUDE>#{include_transactions.to_ofx_102_s}\n" if include_transactions
95
-
92
+ " <INCTRAN>\n" if include_transactions
96
93
  body +=
97
- " <DTSTART>#{included_range.begin.to_ofx_102_s}\n" +
98
- " <DTEND>#{included_range.end.to_ofx_102_s}\n" if included_range
99
-
94
+ " <DTSTART>#{included_range.begin.to_ofx_102_s}\n" +
95
+ " <DTEND>#{included_range.end.to_ofx_102_s}\n" if included_range
96
+ body +=
97
+ " <INCLUDE>#{include_transactions.to_ofx_102_s}\n" if include_transactions
100
98
  body +=
101
99
  " </INCTRAN>" if include_transactions
102
-
103
100
  body
104
101
  end
105
102
 
@@ -136,7 +133,9 @@ module OFX
136
133
 
137
134
  transaction_list_hash = response_hash['BANKTRANLIST']
138
135
  if (transaction_list_hash)
139
- response.transaction_range = transaction_list_hash['DTSTART'].to_datetime..transaction_list_hash['DTEND'].to_datetime
136
+ if transaction_list_hash['DTSTART'] && transaction_list_hash['DTEND']
137
+ response.transaction_range = transaction_list_hash['DTSTART'].to_datetime..transaction_list_hash['DTEND'].to_datetime
138
+ end
140
139
 
141
140
  response.transactions = []
142
141
  transactions = transaction_list_hash['STMTTRN'] if transaction_list_hash['STMTTRN'].kind_of?(Array)
@@ -151,7 +150,7 @@ module OFX
151
150
  transaction.date_initiated = transaction_hash['DTUSER'].to_datetime if transaction_hash['DTUSER']
152
151
  transaction.date_available = transaction_hash['DTAVAIL'].to_datetime if transaction_hash['DTAVAIL']
153
152
 
154
- transaction.amount = transaction_hash['TRNAMT'].to_d
153
+ transaction.amount = transaction_hash['TRNAMT'].to_d if transaction_hash['TRNAMT']
155
154
  transaction.currency = transaction_hash['CURRENCY'] || transaction_hash['ORIGCURRENCY'] || response.default_currency
156
155
 
157
156
  transaction.financial_institution_transaction_identifier = transaction_hash['FITID']
@@ -241,7 +240,10 @@ module OFX
241
240
  statement.currency = closing_hash['CURRENCY'] || closing_hash['ORIGCURRENCY'] || response.default_currency
242
241
 
243
242
  statement.finanical_institution_transaction_identifier = closing_hash['FITID']
244
- statement.statement_range = closing_hash['DTOPEN'].to_date..closing_hash['DTCLOSE'].to_date
243
+
244
+ if closing_hash['DTOPEN'] && closing_hash['DTCLOSE']
245
+ statement.statement_range = closing_hash['DTOPEN'].to_date..closing_hash['DTCLOSE'].to_date
246
+ end
245
247
  statement.next_statement_close = closing_hash['DTNEXT'].to_date if closing_hash['DTNEXT']
246
248
 
247
249
  statement.opening_balance = closing_hash['BALOPEN'].to_d if closing_hash['BALOPEN']
@@ -256,7 +258,9 @@ module OFX
256
258
  statement.debit_adjustements = closing_hash['DEBADJ'].to_d if closing_hash['DEBADJ']
257
259
  statement.credit_limit = closing_hash['CREDITLIMIT'].to_d if closing_hash['CREDITLIMIT']
258
260
 
259
- statement.transaction_range = closing_hash['DTPOSTSTART'].to_date..closing_hash['DTPOSTEND'].to_date
261
+ if closing_hash['DTPOSTSTART'] && closing_hash['DTPOSTEND']
262
+ statement.transaction_range = closing_hash['DTPOSTSTART'].to_date..closing_hash['DTPOSTEND'].to_date
263
+ end
260
264
 
261
265
  statement.marketing_information = closing_hash['MKTGINFO']
262
266
 
@@ -266,4 +270,4 @@ module OFX
266
270
  response
267
271
  end
268
272
  end
269
- end
273
+ end
@@ -37,7 +37,7 @@ module OFX
37
37
  header = OFX::Header.new
38
38
 
39
39
  header_pattern = /^(\w+)\:(.*)$/
40
- header_string.split("\n").each do |this_header|
40
+ header_string.split(%r{\r*\n}).each do |this_header|
41
41
  header_match = header_pattern.match(this_header)
42
42
  header[header_match[1]] = header_match[2]
43
43
  end
@@ -1,17 +1,17 @@
1
1
  # Copyright © 2007 Chris Guidry <chrisguidry@gmail.com>
2
2
  #
3
3
  # This file is part of OFX for Ruby.
4
- #
4
+ #
5
5
  # OFX for Ruby is free software; you can redistribute it and/or modify
6
6
  # it under the terms of the GNU General Public License as published by
7
7
  # the Free Software Foundation; either version 3 of the License, or
8
8
  # (at your option) any later version.
9
- #
9
+ #
10
10
  # OFX for Ruby is distributed in the hope that it will be useful,
11
11
  # but WITHOUT ANY WARRANTY; without even the implied warranty of
12
12
  # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
13
  # GNU General Public License for more details.
14
- #
14
+ #
15
15
  # You should have received a copy of the GNU General Public License
16
16
  # along with this program. If not, see <http://www.gnu.org/licenses/>.
17
17
 
@@ -20,7 +20,6 @@ require File.dirname(__FILE__) + '/header'
20
20
  require File.dirname(__FILE__) + '/message_set'
21
21
  require File.dirname(__FILE__) + '/status'
22
22
  require File.dirname(__FILE__) + '/statements'
23
-
24
23
  require File.dirname(__FILE__) + '/signon_message_set'
25
24
  require File.dirname(__FILE__) + '/signup_message_set'
26
25
  require File.dirname(__FILE__) + '/banking_message_set'
@@ -32,8 +31,9 @@ require File.dirname(__FILE__) + '/payment_message_set'
32
31
  require File.dirname(__FILE__) + '/email_message_set'
33
32
  require File.dirname(__FILE__) + '/investment_security_list_message_set'
34
33
  require File.dirname(__FILE__) + '/financial_institution_profile_message_set'
35
-
36
34
  require File.dirname(__FILE__) + '/parser'
35
+ require 'date'
36
+ require 'time'
37
37
 
38
38
  module OFX
39
39
  module OFX102
@@ -48,32 +48,35 @@ module OFX
48
48
  body += message_set.to_ofx_102_s
49
49
  end
50
50
  body += "</OFX>\n"
51
-
52
- # puts body
53
51
 
54
52
  body
55
53
  end
56
54
 
57
55
  def from_http_response_body(body)
58
- # puts "Raw response:\n#{body}"
59
-
60
- header_pattern = /(\w+\:.*\n)+/
61
- header_match = header_pattern.match(body)
62
-
63
- body = header_match.post_match
64
- header = Header.from_ofx_102_s(header_match[0].strip)
65
-
56
+ body = body.lstrip
57
+
58
+ end_of_header_index = body.index("<OFX>")
59
+
60
+ header_str = body[0...end_of_header_index].strip
61
+ body = body[end_of_header_index..-1]
62
+
63
+ if header_str.nil? || header_str == ""
64
+ raise NotImplementedError, "OFX server returned unmatched ASCII"
65
+ end
66
+
67
+ header = Header.from_ofx_102_s(header_str)
68
+
66
69
  parser = OFX::OFX102::Parser.new
67
70
 
68
71
  parser.scan_str body
69
-
72
+
70
73
  if parser.documents.length > 1
71
74
  raise NotImplementedError, "Multiple response documents"
72
75
  end
73
-
76
+
74
77
  # require 'pp'
75
78
  # pp parser.ofx_hashes[0]
76
-
79
+
77
80
  document = parser.documents[0]
78
81
  document.header = header
79
82
  document
@@ -82,15 +85,34 @@ module OFX
82
85
  end
83
86
  end
84
87
 
85
- require 'date'
86
88
  class Date
87
89
  def to_ofx_102_s
88
90
  strftime('%Y%m%d')
89
91
  end
90
92
  end
91
93
  class DateTime
92
- def to_ofx_102_s
93
- strftime('%Y%m%d%H%M%S')
94
+ def to_time
95
+ Time.parse(self.to_s)
96
+ end
97
+
98
+ def to_ofx_102_s_defunct
99
+ strftime('%Y%m%d%H%M%S.') + (sec_fraction * 86400000000).to_i.to_s + '[' + offset.numerator.to_s + ':' + strftime('%Z') + ']'
100
+ end
101
+
102
+ def to_ofx_102_s(extended=true)
103
+ s = strftime('%Y%m%d%H%M%S')
104
+
105
+ if extended
106
+ # some servers need exactly 3 decimal places for sec_fraction
107
+ s = s + '.000'
108
+
109
+ # use Time class to return TZ in correct format for OFX
110
+ # ie. ("EDT" vs. "-07:00")
111
+ tz = to_time.zone
112
+ s = s + '[0:' + tz + ']' if tz
113
+ end
114
+
115
+ return s
94
116
  end
95
117
  end
96
118
  class String
@@ -113,7 +113,7 @@ module OFX
113
113
  response.language = response_hash['LANGUAGE']
114
114
  response.date_of_last_profile_update = response_hash['DTPROFUP'].to_datetime if response_hash['DTPROFUP']
115
115
  response.date_of_last_account_update = response_hash['DTACCTUP'].to_datetime if response_hash['DTACCTUP']
116
- response.financial_institution_identification = OFX::FinancialInstitutionIdentification.from_ofx_102_hash(response_hash['FI'])
116
+ response.financial_institution_identification = OFX::FinancialInstitutionIdentification.from_ofx_102_hash(response_hash['FI']) if response_hash['FI']
117
117
  #TODO: @session_cookie
118
118
 
119
119
  response
@@ -109,7 +109,14 @@ module OFX
109
109
  def ofx_102_response_body
110
110
  raise NotImplementedError
111
111
  end
112
-
112
+
113
+ def account_identifier(account_id=nil)
114
+ account_id = 0 if not account_id
115
+ info = accounts[account_id].account_information if accounts and accounts.size > account_id
116
+ id = info.account.account_identifier if info
117
+ return id
118
+ end
119
+
113
120
  def self.from_ofx_102_hash(transaction_hash)
114
121
  response = AccountInformationResponse.new
115
122
 
@@ -117,7 +124,10 @@ module OFX
117
124
  response.status = OFX::Status.from_ofx_102_hash(transaction_hash['STATUS'])
118
125
 
119
126
  response_hash = transaction_hash['ACCTINFORS']
120
- response.date_of_last_account_update = response_hash['DTACCTUP'].to_datetime
127
+ if not response_hash
128
+ return response
129
+ end
130
+ response.date_of_last_account_update = response_hash['DTACCTUP'].to_datetime if response_hash['DTACCTUP']
121
131
 
122
132
  response.accounts = []
123
133
  account_infos = response_hash['ACCTINFO'] if response_hash['ACCTINFO'].kind_of?(Array)
@@ -173,6 +183,19 @@ module OFX
173
183
  when 'ACTIVE' then :active
174
184
  else raise NotImplementedError
175
185
  end
186
+ elsif account_info_hash['INVACCTINFO']
187
+ cc_acct_info_hash = account_info_hash['INVACCTINFO']
188
+ account_info.account_information = OFX::CreditCardAccountInformation.new
189
+
190
+ acct_from_hash = cc_acct_info_hash['INVACCTFROM']
191
+ account_info.account_information.account = OFX::CreditCardAccount.new
192
+ account_info.account_information.account.account_identifier = acct_from_hash['ACCTID']
193
+ account_info.account_information.status = case cc_acct_info_hash['SVCSTATUS']
194
+ when 'AVAIL' then :available
195
+ when 'PEND' then :pending
196
+ when 'ACTIVE' then :active
197
+ else raise NotImplementedError
198
+ end
176
199
  else
177
200
  raise NotImplementedError
178
201
  end
@@ -183,4 +206,4 @@ module OFX
183
206
  response
184
207
  end
185
208
  end
186
- end
209
+ end
@@ -42,11 +42,21 @@ module OFX
42
42
  return nil
43
43
  end
44
44
 
45
- def application_identification
46
- OFX::ApplicationIdentification.new('OFX', '0010')
45
+ def application_identification(ofx_client_spoof=nil)
46
+ # Reference: http://wiki.mthbuilt.com/Tweaking_OFX_Connections
47
+ case ofx_client_spoof
48
+ when 'Money'
49
+ OFX::ApplicationIdentification.new('Money', '1600')
50
+ when 'Quicken'
51
+ OFX::ApplicationIdentification.new('QWIN', '1700')
52
+ when 'QuickBooks'
53
+ OFX::ApplicationIdentification.new('QBW', '1800')
54
+ else
55
+ OFX::ApplicationIdentification.new('OFX', '0010')
56
+ end
47
57
  end
48
58
 
49
- def create_signon_request_message(financial_institution_id)
59
+ def create_signon_request_message(financial_institution_id, ofx_client_id=nil)
50
60
  signonMessageSet = OFX::SignonMessageSet.new
51
61
 
52
62
  signonRequest = OFX::SignonRequest.new
@@ -56,7 +66,7 @@ module OFX
56
66
  signonRequest.language = "ENG"
57
67
  signonRequest.financial_institution_identification = self.financial_institution_identification_for(financial_institution_id)
58
68
  signonRequest.session_cookie = nil
59
- signonRequest.application_identification = self.application_identification
69
+ signonRequest.application_identification = self.application_identification(ofx_client_id)
60
70
  signonRequest.client_unique_identifier = self.client_unique_identifier
61
71
  signonMessageSet.requests << signonRequest
62
72
 
@@ -20,16 +20,44 @@ require 'uri'
20
20
  module OFX
21
21
  class FinancialInstitution
22
22
 
23
- def self.get_institution(financial_institution_name)
23
+ def self.get_institution(financial_institution_name, ofx_client_id=nil, ssl_version=nil)
24
24
  case financial_institution_name
25
25
  when 'Capital One'
26
26
  FinancialInstitution.new('Capital One',
27
- URI.parse('https://onlinebanking.capitalone.com/scripts/serverext.dll'),
28
- OFX::Version.new("1.0.2"))
27
+ URI.parse('https://onlinebanking.capitalone.com/ofx/process.ofx'),
28
+ OFX::Version.new("1.0.2"),
29
+ 'Hibernia', '1001', '065002030',
30
+ ofx_client_id, ssl_version)
29
31
  when 'Citi'
30
32
  FinancialInstitution.new('Citi',
31
- URI.parse('https://secureofx2.bankhost.com/citi/cgi-forte/ofx_rt?servicename=ofx_rt&pagename=ofx'),
32
- OFX::Version.new("1.0.2"))
33
+ URI.parse('https://www.accountonline.com/cards/svc/CitiOfxManager.do'),
34
+ OFX::Version.new("1.0.2"),
35
+ 'Citigroup', '24909', nil,
36
+ 'Quicken', ssl_version)
37
+ when 'Chase'
38
+ FinancialInstitution.new('Chase',
39
+ URI.parse('https://ofx.chase.com'),
40
+ OFX::Version.new("1.0.3"),
41
+ 'B1', '10898', nil,
42
+ 'Quicken', :TLSv1)
43
+ when 'AMEX'
44
+ FinancialInstitution.new('AMEX',
45
+ URI.parse('https://online.americanexpress.com/myca/ofxdl/desktop/desktopDownload.do?request_type=nl_ofxdownload'),
46
+ OFX::Version.new("1.0.2"),
47
+ 'AMEX', '3101', nil,
48
+ 'Quicken', ssl_version)
49
+ when 'Schwab'
50
+ FinancialInstitution.new('Schwab',
51
+ URI.parse('https://ofx.schwab.com/bankcgi_dev/ofx_server'),
52
+ OFX::Version.new("1.0.2"),
53
+ 'ISC', '101', '121202211',
54
+ 'Quicken', ssl_version)
55
+ when 'Fidelity'
56
+ FinancialInstitution.new('Fidelity',
57
+ URI.parse('https://ofx.fidelity.com/ftgw/OFX/clients/download'),
58
+ OFX::Version.new("1.0.2"),
59
+ 'fidelity.com', '7776', nil,
60
+ 'Quicken', ssl_version)
33
61
  else
34
62
  raise NotImplementedError
35
63
  end
@@ -38,11 +66,39 @@ module OFX
38
66
  attr :name
39
67
  attr :ofx_uri
40
68
  attr :ofx_version
69
+ attr :organization_name
70
+ attr :organization_id
71
+ attr :bank_identifier
72
+ attr :client
41
73
 
42
- def initialize(name, ofx_uri, ofx_version)
74
+ def initialize(name, ofx_uri, ofx_version, org_name, org_id, bank_id=nil, client_id=nil, ssl_version=nil)
43
75
  @name = name
44
76
  @ofx_uri = ofx_uri
45
77
  @ofx_version = ofx_version
78
+ @organization_name = org_name
79
+ @organization_id = org_id
80
+ @bank_identifier = bank_id
81
+ @client = nil
82
+ @ofx_client_id = client_id
83
+ @ofx_ssl_version = ssl_version
84
+ end
85
+
86
+ def set_client(user_name, password, client_uid=nil)
87
+ inst_id = OFX::FinancialInstitutionIdentification.new(
88
+ @organization_name, @organization_id)
89
+ user_cred = OFX::UserCredentials.new(user_name, password)
90
+ @client = OFX::FinancialClient.new([[inst_id, user_cred]])
91
+ # caller can generate one-time with: SecureRandom.hex(16)
92
+ # see: http://wiki.gnucash.org/wiki/Setting_up_OFXDirectConnect_in_GnuCash_2#Chase_.22username_or_password_are_incorrect.22
93
+ @client.client_unique_identifier = client_uid
94
+ @client
95
+ end
96
+
97
+ # anonymous can be used for ProfileRequest
98
+ def set_client_anon
99
+ user_name = "anonymous00000000000000000000000"
100
+ password = "anonymous00000000000000000000000"
101
+ set_client(user_name, password)
46
102
  end
47
103
 
48
104
  def create_request_document()
@@ -62,26 +118,173 @@ module OFX
62
118
  end
63
119
 
64
120
  document.header.security = "NONE"
65
-
66
121
  document.header.content_encoding = "USASCII"
67
122
  document.header.content_character_set = "1252"
68
-
69
123
  document.header.compression = "NONE"
70
-
71
124
  document.header.previous_unique_identifier = "NONE"
72
125
  document.header.unique_identifier = OFX::FileUniqueIdentifier.new
73
126
 
74
127
  document
75
128
  end
76
129
 
130
+ def create_request_document_signon
131
+ return nil if @client.nil?
132
+ requestDocument = self.create_request_document
133
+ requestDocument.message_sets << @client.create_signon_request_message(@organization_id, @ofx_client_id)
134
+ return requestDocument
135
+ end
136
+
137
+ def create_request_document_profile_update(request_date=nil)
138
+ return nil if @client.nil?
139
+ if request_date.nil?
140
+ request_date = DateTime.new(2001, 1, 1)
141
+ end
142
+ profileMessageSet = OFX::FinancialInstitutionProfileMessageSet.new
143
+ profileRequest = OFX::FinancialInstitutionProfileRequest.new
144
+ profileRequest.transaction_identifier = OFX::TransactionUniqueIdentifier.new
145
+ profileRequest.client_routing = 'MSGSET'
146
+ profileRequest.date_of_last_profile_update = request_date
147
+ profileMessageSet.requests << profileRequest
148
+
149
+ requestDocument = self.create_request_document
150
+ requestDocument.message_sets << @client.create_signon_request_message(@organization_id, @ofx_client_id)
151
+ requestDocument.message_sets << profileMessageSet
152
+ return requestDocument
153
+ end
154
+
155
+ def create_request_document_signup(request_date=nil)
156
+ return nil if @client.nil?
157
+ if request_date.nil?
158
+ request_date = DateTime.new(2001, 1, 1)
159
+ end
160
+ signup_message_set = OFX::SignupMessageSet.new
161
+ account_info_request = OFX::AccountInformationRequest.new
162
+ account_info_request.transaction_identifier = OFX::TransactionUniqueIdentifier.new
163
+ account_info_request.date_of_last_account_update = request_date
164
+ signup_message_set.requests << account_info_request
165
+
166
+ requestDocument = self.create_request_document
167
+ requestDocument.message_sets << @client.create_signon_request_message(@organization_id, @ofx_client_id)
168
+ requestDocument.message_sets << signup_message_set
169
+ return requestDocument
170
+ end
171
+
172
+ def create_request_document_for_cc_statement(account_id, date_range=nil, include_trans=true)
173
+ return nil if @client.nil?
174
+ cc_message_set = OFX::CreditCardStatementMessageSet.new
175
+ statement_request = OFX::CreditCardStatementRequest.new
176
+ statement_request.transaction_identifier = OFX::TransactionUniqueIdentifier.new
177
+ statement_request.account = OFX::CreditCardAccount.new
178
+ statement_request.account.account_identifier = account_id
179
+ if include_trans
180
+ statement_request.included_range = date_range
181
+ statement_request.include_transactions = include_trans
182
+ end
183
+ cc_message_set.requests << statement_request
184
+
185
+ requestDocument = self.create_request_document
186
+ requestDocument.message_sets << @client.create_signon_request_message(@organization_id, @ofx_client_id)
187
+ requestDocument.message_sets << cc_message_set
188
+ return requestDocument
189
+ end
190
+
191
+ def create_request_document_for_cc_closing_statement(account_id)
192
+ create_request_document_for_cc_statement(account_id, nil, false)
193
+ end
194
+
195
+ def create_request_document_for_bank_statement(account_id, date_range=nil, account_type = :checking)
196
+ return nil if @client.nil?
197
+ banking_message_set = OFX::BankingMessageSet.new
198
+ statement_request = OFX::BankingStatementRequest.new
199
+ statement_request.transaction_identifier = OFX::TransactionUniqueIdentifier.new
200
+ statement_request.account = OFX::BankingAccount.new
201
+ statement_request.account.bank_identifier = @bank_identifier
202
+ statement_request.account.branch_identifier = nil
203
+ statement_request.account.account_identifier = account_id
204
+ statement_request.account.account_type = account_type
205
+ statement_request.account.account_key = nil
206
+ statement_request.include_transactions = true if date_range
207
+ statement_request.included_range = date_range # example DateRange (start.to_date)..(end.to_date)
208
+ banking_message_set.requests << statement_request
209
+
210
+ requestDocument = self.create_request_document
211
+ requestDocument.message_sets << @client.create_signon_request_message(@organization_id, @ofx_client_id)
212
+ requestDocument.message_sets << banking_message_set
213
+ return requestDocument
214
+ end
215
+
216
+ def create_request_document_for_inv_statement(account_id, date_range=nil)
217
+ return nil if @client.nil?
218
+ inv_message_set = OFX::InvestmentStatementMessageSet.new
219
+ statement_request = OFX::BankingStatementRequest.new
220
+ statement_request.transaction_identifier = OFX::TransactionUniqueIdentifier.new
221
+ statement_request.account = OFX::BankingAccount.new
222
+ statement_request.account.bank_identifier = @bank_identifier
223
+ statement_request.account.branch_identifier = nil
224
+ statement_request.account.account_identifier = account_id
225
+ statement_request.account.account_type = :money_market
226
+ statement_request.account.account_key = nil
227
+ statement_request.include_transactions = true if date_range
228
+ statement_request.included_range = date_range
229
+ inv_message_set.requests << statement_request
230
+
231
+ requestDocument = self.create_request_document
232
+ requestDocument.message_sets << @client.create_signon_request_message(@organization_id, @ofx_client_id)
233
+ requestDocument.message_sets << inv_message_set
234
+ return requestDocument
235
+ end
236
+
237
+ def get_account_id(account_id=nil)
238
+ req = create_request_document_signup
239
+ return nil if req.nil?
240
+ resp = send(req)
241
+ id = resp.message_sets[1].responses[0].account_identifier(account_id) if resp
242
+ return id
243
+ end
244
+
77
245
  def send(document)
78
246
  serializer = OFX::Serializer.get(@ofx_version)
79
247
  request_body = serializer.to_http_post_body(document)
80
248
 
81
249
  client = OFX::HTTPClient.new(@ofx_uri)
82
- response_body = client.send(request_body)
250
+ response_body = client.send(request_body, @ofx_ssl_version)
83
251
 
84
252
  return serializer.from_http_response_body(response_body)
85
253
  end
254
+
255
+ ##
256
+ ## Debugging routines
257
+ ##
258
+ def get_anon_profile
259
+ set_client_anon
260
+ return send(create_request_document_profile_update)
261
+ end
262
+
263
+ def document_to_post_data(document, no_whitespace=false)
264
+ serializer = OFX::Serializer.get(@ofx_version)
265
+ request_body = serializer.to_http_post_body(document)
266
+ if no_whitespace
267
+ request_body.delete! " "
268
+ end
269
+ return request_body
270
+ end
271
+
272
+ def test_send(data, post_data=nil, serial_resp=true, debug_req=false, debug_resp=false)
273
+ serializer = OFX::Serializer.get(@ofx_version)
274
+ if post_data
275
+ request_body = data
276
+ else
277
+ request_body = serializer.to_http_post_body(data)
278
+ end
279
+
280
+ client = OFX::HTTPClient.new(@ofx_uri)
281
+ response_body = client.send(request_body, @ofx_ssl_version, debug_req, debug_resp)
282
+
283
+ if serial_resp
284
+ return serializer.from_http_response_body(response_body)
285
+ else
286
+ return response_body
287
+ end
288
+ end
86
289
  end
87
290
  end