ofx_for_ruby 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.externalToolBuilders/Rebuild parsers.launch +10 -0
- data/.gitignore +9 -0
- data/.loadpath +5 -0
- data/.project +27 -0
- data/COPYING +674 -0
- data/Gemfile +2 -0
- data/README +47 -0
- data/RELEASE_NOTES +45 -0
- data/Rakefile +63 -0
- data/lib/ofx.rb +60 -0
- data/lib/ofx/1.0.2/banking_message_set.rb +261 -0
- data/lib/ofx/1.0.2/credit_card_statement_message_set.rb +269 -0
- data/lib/ofx/1.0.2/document.rb +34 -0
- data/lib/ofx/1.0.2/email_message_set.rb +34 -0
- data/lib/ofx/1.0.2/financial_institution_profile_message_set.rb +155 -0
- data/lib/ofx/1.0.2/header.rb +48 -0
- data/lib/ofx/1.0.2/interbank_funds_transfer_message_set.rb +30 -0
- data/lib/ofx/1.0.2/investment_security_list_message_set.rb +30 -0
- data/lib/ofx/1.0.2/investment_statement_message_set.rb +30 -0
- data/lib/ofx/1.0.2/lexer.rb +135 -0
- data/lib/ofx/1.0.2/message_set.rb +165 -0
- data/lib/ofx/1.0.2/ofx_102.racc +90 -0
- data/lib/ofx/1.0.2/ofx_102.rex +65 -0
- data/lib/ofx/1.0.2/parser.rb +215 -0
- data/lib/ofx/1.0.2/payment_message_set.rb +30 -0
- data/lib/ofx/1.0.2/serializer.rb +114 -0
- data/lib/ofx/1.0.2/signon_message_set.rb +121 -0
- data/lib/ofx/1.0.2/signup_message_set.rb +186 -0
- data/lib/ofx/1.0.2/statements.rb +54 -0
- data/lib/ofx/1.0.2/status.rb +30 -0
- data/lib/ofx/1.0.2/wire_funds_transfer_message_set.rb +30 -0
- data/lib/ofx/banking_message_set.rb +125 -0
- data/lib/ofx/credit_card_statement_message_set.rb +104 -0
- data/lib/ofx/document.rb +30 -0
- data/lib/ofx/email_message_set.rb +42 -0
- data/lib/ofx/file_unique_identifier.rb +28 -0
- data/lib/ofx/financial_client.rb +76 -0
- data/lib/ofx/financial_institution.rb +83 -0
- data/lib/ofx/financial_institution_profile_message_set.rb +67 -0
- data/lib/ofx/header.rb +115 -0
- data/lib/ofx/http/cacert.pem +3509 -0
- data/lib/ofx/http/ofx_http_client.rb +84 -0
- data/lib/ofx/interbank_funds_transfer_message_set.rb +33 -0
- data/lib/ofx/investment_security_list_message_set.rb +33 -0
- data/lib/ofx/investment_statement_message_set.rb +33 -0
- data/lib/ofx/message_set.rb +78 -0
- data/lib/ofx/payment_message_set.rb +33 -0
- data/lib/ofx/serializer.rb +39 -0
- data/lib/ofx/signon_message_set.rb +141 -0
- data/lib/ofx/signup_message_set.rb +84 -0
- data/lib/ofx/statements.rb +49 -0
- data/lib/ofx/status.rb +100 -0
- data/lib/ofx/transaction_unique_identifier.rb +28 -0
- data/lib/ofx/version.rb +82 -0
- data/lib/ofx/wire_funds_transfer_message_set.rb +33 -0
- data/ofx_for_ruby.gemspec +25 -0
- data/planning/OFX Specification completion.ods +0 -0
- data/test/capital_one/capital_one_helper.rb +77 -0
- data/test/capital_one/fixtures/README +10 -0
- data/test/capital_one/fixtures/fipid-5599.xml +98 -0
- data/test/capital_one/test_banking_statement.rb +108 -0
- data/test/capital_one/test_financial_institution_profile.rb +295 -0
- data/test/capital_one/test_ofx_http_client.rb +72 -0
- data/test/capital_one/test_signup_account_information.rb +100 -0
- data/test/citi/citi_helper.rb +77 -0
- data/test/citi/fixtures/README +9 -0
- data/test/citi/fixtures/fipid-6642.xml +98 -0
- data/test/citi/test_credit_card_statement.rb +159 -0
- data/test/citi/test_financial_institution_profile.rb +231 -0
- data/test/citi/test_ofx_http_client.rb +71 -0
- data/test/citi/test_signup_account_information.rb +85 -0
- data/test/test_helper.rb +4 -0
- data/test/test_ofx_version.rb +141 -0
- metadata +210 -0
data/Gemfile
ADDED
data/README
ADDED
@@ -0,0 +1,47 @@
|
|
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.
|
2
|
+
|
3
|
+
---------------------------------------
|
4
|
+
|
5
|
+
OFX for Ruby is a pure Ruby implementation of Open Financial Exchange specifications (1.0.2 through 2.1.1) for building both financial
|
6
|
+
clients and servers, providing parsers/serializers for each version, and a uniform object model across all versions.
|
7
|
+
|
8
|
+
Copyright © 2007 Chris Guidry <chrisguidry@gmail.com>.
|
9
|
+
OFX for Ruby is distributed under the GNU Public License, version 3. See COPYING for more information.
|
10
|
+
|
11
|
+
|
12
|
+
Discovering Financial Institution connection information:
|
13
|
+
There is currently no discovery mechanism within OFX for Ruby for acquiring financial institution connection information from any partner servers (although this is planned in the future). Finding out this information is currently a manual process, but is greatly facilitated with either the ofxconnect utility from libofx <http://libofx.sourceforge.net/> or the information available at <http://wiki.gnucash.org/wiki/OFX_Direct_Connect_Bank_Settings>.
|
14
|
+
|
15
|
+
|
16
|
+
Running Unit Tests:
|
17
|
+
There are unit tests in the test directory, and I intend to keep these correct and functional to the best of my abilities. I am, however, limited in the coverage I can generate, since I am currently testing live against my own personal bank and credit card accounts. For the near future, the unit test suite will only cover the read-only aspects of communicating over OFX. So as of now, the unit tests available are a little specific to Capital One and CitiCards accounts.
|
18
|
+
|
19
|
+
If you have an account with one of these institutions, great! Please help me test more scenarios with these banks.
|
20
|
+
If you have an account with any other institution and can extend OFX for Ruby and it's unit test suite, greater!!!
|
21
|
+
|
22
|
+
In either case, please take care not to leave bank account numbers, and especially user credentials in the source tree when committing. I'm going to try to get a more organized test suite together in the future as we add more financial institutions and automatic discovery to the mix.
|
23
|
+
|
24
|
+
|
25
|
+
OFX Specification Completeness:
|
26
|
+
For the current level of OFX support, please see the "OFX Specification completion.ods" file in the planning directory of the release. This file will also be updated periodically on the RubyForge documentation section of the OFX for Ruby site.
|
27
|
+
|
28
|
+
|
29
|
+
Source Code:
|
30
|
+
Thanks to RubyForge.org for hosting the code for OFX.
|
31
|
+
|
32
|
+
This release can be found in the Subversion repository at <svn://rubyforge.org/var/svn/ofx/tags/ofx-0.1.0>.
|
33
|
+
The latest version can be found at <svn://rubyforge.org/var/svn/ofx/trunk>.
|
34
|
+
|
35
|
+
Distribution Contents:
|
36
|
+
documentation - (one day) this will house all of the documentation for OFX for Ruby
|
37
|
+
lib - the source code for the OFX for Ruby library; (Hint: you can use this folder in your vendor folder in a Rails application)
|
38
|
+
lib/ofx.rb - the primary include file for the library
|
39
|
+
planning - files that I use to keep on track
|
40
|
+
test - the almighty unit test suite (see "Running Unit Tests", above)
|
41
|
+
COPYING - the GPLv3
|
42
|
+
README - this file
|
43
|
+
RELEASE_NOTES - a play-by-play of each OFX for Ruby release (Hint: the 0.1.0 RELEASE_NOTES are the same as this README)
|
44
|
+
|
45
|
+
|
46
|
+
Mailing Lists:
|
47
|
+
ofx-commits@rubyforge.org - notifications of each commit to the OFX tree
|
data/RELEASE_NOTES
ADDED
@@ -0,0 +1,45 @@
|
|
1
|
+
OFX for Ruby
|
2
|
+
currently at version 0.1.0
|
3
|
+
|
4
|
+
==============================================================================
|
5
|
+
|
6
|
+
version 0.1.0
|
7
|
+
2007.07.15
|
8
|
+
first public release
|
9
|
+
<svn://rubyforge.org/var/svn/ofx/tags/ofx-0.1.0>
|
10
|
+
Chris Guidry <chrisguidry@gmail.com>
|
11
|
+
|
12
|
+
Discovering Financial Institution connection information:
|
13
|
+
There is currently no discovery mechanism within OFX for Ruby for acquiring financial institution connection information from any partner servers (although this is planned in the future). Finding out this information is currently a manual process, but is greatly facilitated with either the ofxconnect utility from libofx <http://libofx.sourceforge.net/> or the information available at <http://wiki.gnucash.org/wiki/OFX_Direct_Connect_Bank_Settings>.
|
14
|
+
|
15
|
+
|
16
|
+
Running Unit Tests:
|
17
|
+
There are unit tests in the test directory, and I intend to keep these correct and functional to the best of my abilities. I am, however, limited in the coverage I can generate, since I am currently testing live against my own personal bank and credit card accounts. For the near future, the unit test suite will only cover the read-only aspects of communicating over OFX. So as of now, the unit tests available are a little specific to Capital One and CitiCards accounts.
|
18
|
+
|
19
|
+
If you have an account with one of these institutions, great! Please help me test more scenarios with these banks.
|
20
|
+
If you have an account with any other institution and can extend OFX for Ruby and it's unit test suite, greater!!!
|
21
|
+
|
22
|
+
In either case, please take care not to leave bank account numbers, and especially user credentials in the source tree when committing. I'm going to try to get a more organized test suite together in the future as we add more financial institutions and automatic discovery to the mix.
|
23
|
+
|
24
|
+
|
25
|
+
OFX Specification Completeness:
|
26
|
+
For the current level of OFX support, please see the "OFX Specification completion.ods" file in the planning directory of the release. This file will also be updated periodically on the RubyForge documentation section of the OFX for Ruby site.
|
27
|
+
|
28
|
+
|
29
|
+
Source Code:
|
30
|
+
Thanks to RubyForge.org for hosting the code for OFX.
|
31
|
+
|
32
|
+
This release can be found in the Subversion repository at <svn://rubyforge.org/var/svn/ofx/tags/ofx-0.1.0>.
|
33
|
+
The latest version can be found at <svn://rubyforge.org/var/svn/ofx/trunk>.
|
34
|
+
|
35
|
+
Distribution Contents:
|
36
|
+
documentation - (one day) this will house all of the documentation for OFX for Ruby
|
37
|
+
lib - the source code for the OFX for Ruby library; (Hint: you can use this folder in your vendor folder in a Rails application)
|
38
|
+
lib/ofx.rb - the primary include file for the library
|
39
|
+
planning - files that I use to keep on track
|
40
|
+
test - the almighty unit test suite (see "Running Unit Tests", above)
|
41
|
+
COPYING - the GPLv3
|
42
|
+
README - this file
|
43
|
+
RELEASE_NOTES - a play-by-play of each OFX for Ruby release (Hint: the 0.1.0 RELEASE_NOTES are the same as this README)
|
44
|
+
|
45
|
+
==============================================================================
|
data/Rakefile
ADDED
@@ -0,0 +1,63 @@
|
|
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 'bundler/setup'
|
19
|
+
Bundler::GemHelper.install_tasks
|
20
|
+
|
21
|
+
require 'rake'
|
22
|
+
require 'rake/clean'
|
23
|
+
require 'rake/testtask'
|
24
|
+
require 'rake/rdoctask'
|
25
|
+
|
26
|
+
|
27
|
+
Rake::TestTask.new do |t|
|
28
|
+
t.test_files = FileList['test/**/test_*.rb']
|
29
|
+
t.verbose = true
|
30
|
+
end
|
31
|
+
|
32
|
+
Rake::RDocTask.new do |rd|
|
33
|
+
rd.title = "OFX - an OFX implementation for Ruby"
|
34
|
+
rd.rdoc_files.include("lib/**/*.rb")
|
35
|
+
rd.rdoc_files.exclude("lib/**/parser.rb")
|
36
|
+
rd.rdoc_files.exclude("lib/**/lexer.rb")
|
37
|
+
rd.rdoc_dir = "documentation/api"
|
38
|
+
end
|
39
|
+
|
40
|
+
# RCOV command, run as though from the commandline. Amend as required or perhaps move to config/environment.rb?
|
41
|
+
RCOV = "bundle exec rcov -Ilib --xref --profile"
|
42
|
+
|
43
|
+
desc "generate a unit coverage report in coverage"
|
44
|
+
task :"coverage" do
|
45
|
+
sh "#{RCOV} --output coverage test/test_*.rb test/**/test_*.rb"
|
46
|
+
end
|
47
|
+
|
48
|
+
desc "runs coverage and rdoc"
|
49
|
+
task :default => [:coverage, :rdoc]
|
50
|
+
|
51
|
+
|
52
|
+
desc "recreates parsers"
|
53
|
+
task :parsers do
|
54
|
+
sh "cd lib/ofx/1.0.2; bundle exec rex -o lexer.rb ofx_102.rex"
|
55
|
+
sh "cd lib/ofx/1.0.2; bundle exec racc -o parser.rb ofx_102.racc"
|
56
|
+
end
|
57
|
+
|
58
|
+
task :test => :parsers
|
59
|
+
task :coverage => :parsers
|
60
|
+
task :rdoc => :parsers
|
61
|
+
task :build => :parsers
|
62
|
+
task :release => :parsers
|
63
|
+
task :install => :parsers
|
data/lib/ofx.rb
ADDED
@@ -0,0 +1,60 @@
|
|
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 'active_support'
|
19
|
+
require 'uri'
|
20
|
+
require 'cgi'
|
21
|
+
|
22
|
+
require 'bigdecimal'
|
23
|
+
require 'bigdecimal/util'
|
24
|
+
|
25
|
+
require 'ofx/version'
|
26
|
+
require 'ofx/status'
|
27
|
+
require 'ofx/file_unique_identifier'
|
28
|
+
require 'ofx/transaction_unique_identifier'
|
29
|
+
require 'ofx/header'
|
30
|
+
require 'ofx/message_set'
|
31
|
+
require 'ofx/document'
|
32
|
+
require 'ofx/statements'
|
33
|
+
|
34
|
+
require 'ofx/financial_institution'
|
35
|
+
require 'ofx/financial_client'
|
36
|
+
|
37
|
+
require 'ofx/signon_message_set'
|
38
|
+
require 'ofx/signup_message_set'
|
39
|
+
require 'ofx/banking_message_set'
|
40
|
+
require 'ofx/credit_card_statement_message_set'
|
41
|
+
require 'ofx/investment_statement_message_set'
|
42
|
+
require 'ofx/interbank_funds_transfer_message_set'
|
43
|
+
require 'ofx/wire_funds_transfer_message_set'
|
44
|
+
require 'ofx/payment_message_set'
|
45
|
+
require 'ofx/email_message_set'
|
46
|
+
require 'ofx/investment_security_list_message_set'
|
47
|
+
require 'ofx/financial_institution_profile_message_set'
|
48
|
+
|
49
|
+
require 'ofx/serializer'
|
50
|
+
|
51
|
+
require 'ofx/http/ofx_http_client.rb'
|
52
|
+
|
53
|
+
# = Summary
|
54
|
+
# An implementation of the OFX specification for financial systems
|
55
|
+
# integration.
|
56
|
+
#
|
57
|
+
# = Specifications
|
58
|
+
# OFX 1.0.2:: http://www.ofx.net/ofx/downloads/ofx102spec.zip
|
59
|
+
module OFX
|
60
|
+
end
|
@@ -0,0 +1,261 @@
|
|
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 BankingMessageSet < MessageSet
|
20
|
+
def ofx_102_message_set_name
|
21
|
+
'BANK'
|
22
|
+
end
|
23
|
+
|
24
|
+
def request_or_response_from_ofx_102_tag_name(response_or_request_name)
|
25
|
+
case response_or_request_name
|
26
|
+
when "STMTTRNRQ" then BankingStatementRequest.new
|
27
|
+
when "STMTTRNRS" then BankingStatementResponse.new
|
28
|
+
else raise NotImplementedError, response_or_request_name
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def self.from_ofx_102_hash(message_set_hash)
|
33
|
+
message_set = BankingMessageSet.new
|
34
|
+
|
35
|
+
message_set_hash.each_pair() do |transaction_name, transaction_hash|
|
36
|
+
case transaction_name
|
37
|
+
when "STMTTRNRQ" then message_set.requests << BankingStatementRequest.from_ofx_102_hash(transaction_hash)
|
38
|
+
when "STMTTRNRS" then message_set.responses << BankingStatementResponse.from_ofx_102_hash(transaction_hash)
|
39
|
+
else raise NotImplementedError, transaction_name
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
return message_set
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
class BankingMessageSetProfile < MessageSetProfile
|
48
|
+
def self.from_ofx_102_hash(message_set_description_hash)
|
49
|
+
profile = OFX::BankingMessageSetProfile.new
|
50
|
+
profile.message_set_class = OFX::BankingMessageSet
|
51
|
+
profile.from_ofx_102_hash(message_set_description_hash)
|
52
|
+
|
53
|
+
profile.invalid_account_types = []
|
54
|
+
if message_set_description_hash['INVALIDACCTTYPE']
|
55
|
+
message_set_description_hash['INVALIDACCTTYPE'].each do |invalid_acct_type|
|
56
|
+
profile.invalid_account_types << BankingAccount.ofx_102_s_to_account_type(invalid_acct_type)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
profile.closing_statement_available = message_set_description_hash['CLOSINGAVAIL'] == 'Y'
|
61
|
+
|
62
|
+
intrabank_profile_hash = message_set_description_hash['XFERPROF']
|
63
|
+
if (intrabank_profile_hash)
|
64
|
+
profile.intrabank_transfer_profile = OFX::IntrabankTransferProfile.new
|
65
|
+
|
66
|
+
days_off = intrabank_profile_hash['PROCDAYSOFF']
|
67
|
+
profile.intrabank_transfer_profile.processing_days_off = []
|
68
|
+
if days_off
|
69
|
+
days_off.each { |day| profile.intrabank_transfer_profile.processing_days_off << day }
|
70
|
+
end
|
71
|
+
profile.intrabank_transfer_profile.processing_end_time_of_day = intrabank_profile_hash['PROCENDTM'].to_time if intrabank_profile_hash['PROCENDTM']
|
72
|
+
profile.intrabank_transfer_profile.supports_scheduled_transfers = intrabank_profile_hash['CANSCHED'] == 'Y'
|
73
|
+
profile.intrabank_transfer_profile.supports_recurring_transfers = intrabank_profile_hash['CANRECUR'] == 'Y'
|
74
|
+
profile.intrabank_transfer_profile.supports_modification_of_transfers = intrabank_profile_hash['CANMODXFERS'] == 'Y'
|
75
|
+
profile.intrabank_transfer_profile.supports_modification_of_models = intrabank_profile_hash['CANMODMDLS'] == 'Y'
|
76
|
+
profile.intrabank_transfer_profile.model_window = intrabank_profile_hash['MODELWND'].to_i
|
77
|
+
profile.intrabank_transfer_profile.number_of_days_early_funds_are_withdrawn = intrabank_profile_hash['DAYSWITH'].to_i
|
78
|
+
profile.intrabank_transfer_profile.default_number_of_days_to_pay = intrabank_profile_hash['DFLTDAYSTOPAY'].to_i
|
79
|
+
end
|
80
|
+
|
81
|
+
stop_check_profile_hash = message_set_description_hash['STPCHKPROF']
|
82
|
+
if (stop_check_profile_hash)
|
83
|
+
profile.stop_check_profile = OFX::StopCheckProfile.new
|
84
|
+
|
85
|
+
days_off = stop_check_profile_hash['PROCDAYSOFF']
|
86
|
+
profile.stop_check_profile.processing_days_off = []
|
87
|
+
if days_off
|
88
|
+
days_off.each { |day| profile.stop_check_profile.processing_days_off << day }
|
89
|
+
end
|
90
|
+
profile.stop_check_profile.processing_end_time_of_day = stop_check_profile_hash['PROCENDTM'].to_time if stop_check_profile_hash['PROCENDTM']
|
91
|
+
profile.stop_check_profile.can_stop_a_range_of_checks = stop_check_profile_hash['CANUSERANGE'] == 'Y'
|
92
|
+
profile.stop_check_profile.can_stop_checks_by_description = stop_check_profile_hash['CANUSEDESC'] == 'Y'
|
93
|
+
profile.stop_check_profile.default_stop_check_fee = stop_check_profile_hash['STPCHKFEE']
|
94
|
+
end
|
95
|
+
|
96
|
+
email_profile_hash = message_set_description_hash['EMAILPROF']
|
97
|
+
if (email_profile_hash)
|
98
|
+
profile.email_profile = OFX::BankingEmailProfile.new
|
99
|
+
profile.email_profile.supports_banking_email = email_profile_hash['CANEMAIL'] == 'Y'
|
100
|
+
profile.email_profile.supports_notifications = email_profile_hash['CANNOTIFY'] == 'Y'
|
101
|
+
end
|
102
|
+
|
103
|
+
profile
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
class BankingAccount
|
108
|
+
def to_ofx_102_request_body
|
109
|
+
body = []
|
110
|
+
body << " <BANKACCTFROM>"
|
111
|
+
body << " <BANKID>#{bank_identifier}"
|
112
|
+
body << " <BRANCHID>#{branch_identifier}" if branch_identifier
|
113
|
+
body << " <ACCTID>#{account_identifier}"
|
114
|
+
body << " <ACCTTYPE>#{BankingAccount.account_type_to_ofx_102_s(account_type)}"
|
115
|
+
body << " <ACCTKEY>#{account_key}" if account_key
|
116
|
+
body << " </BANKACCTFROM>"
|
117
|
+
body.join("\n")
|
118
|
+
end
|
119
|
+
|
120
|
+
def self.ofx_102_s_to_account_type(account_type)
|
121
|
+
case account_type
|
122
|
+
when 'CHECKING' then :checking
|
123
|
+
when 'SAVINGS' then :savings
|
124
|
+
when 'MONEYMRKT' then :money_market
|
125
|
+
when 'CREDITLINE' then :line_of_credit
|
126
|
+
else raise NotImplementedError
|
127
|
+
end
|
128
|
+
end
|
129
|
+
def self.account_type_to_ofx_102_s(account_type)
|
130
|
+
case account_type
|
131
|
+
when :checking then 'CHECKING'
|
132
|
+
when :savings then 'SAVINGS'
|
133
|
+
when :money_market then 'MONEYMRKT'
|
134
|
+
when :line_of_credit then 'CREDITLINE'
|
135
|
+
else raise NotImplementedError
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
def self.from_ofx_102_hash(account_hash)
|
140
|
+
account = OFX::BankingAccount.new
|
141
|
+
|
142
|
+
account.bank_identifier = account_hash['BANKID']
|
143
|
+
account.branch_identifier = account_hash['BRANCHID']
|
144
|
+
account.account_identifier = account_hash['ACCTID']
|
145
|
+
account.account_type = BankingAccount.ofx_102_s_to_account_type(account_hash['ACCTTYPE'])
|
146
|
+
account.account_key = account_hash['ACCTKEY']
|
147
|
+
|
148
|
+
account
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
class BankingStatementRequest < TransactionalRequest
|
153
|
+
def ofx_102_name
|
154
|
+
'STMT'
|
155
|
+
end
|
156
|
+
def ofx_102_request_body
|
157
|
+
body = ""
|
158
|
+
|
159
|
+
body += account.to_ofx_102_request_body
|
160
|
+
|
161
|
+
body +=
|
162
|
+
" <INCTRAN>\n"
|
163
|
+
|
164
|
+
body +=
|
165
|
+
" <DTSTART>#{included_range.begin.to_ofx_102_s}\n" +
|
166
|
+
" <DTEND>#{included_range.end.to_ofx_102_s}\n" if included_range
|
167
|
+
body +=
|
168
|
+
" <INCLUDE>#{include_transactions.to_ofx_102_s}\n" if include_transactions
|
169
|
+
|
170
|
+
body +=
|
171
|
+
" </INCTRAN>" if include_transactions
|
172
|
+
|
173
|
+
body
|
174
|
+
end
|
175
|
+
|
176
|
+
def self.from_ofx_102_hash(transaction_hash)
|
177
|
+
raise NotImplementedError
|
178
|
+
end
|
179
|
+
end
|
180
|
+
|
181
|
+
class BankingStatementResponse < TransactionalResponse
|
182
|
+
def ofx_102_name
|
183
|
+
'STMT'
|
184
|
+
end
|
185
|
+
|
186
|
+
def ofx_102_response_body
|
187
|
+
raise NotImplementedError
|
188
|
+
end
|
189
|
+
|
190
|
+
def self.from_ofx_102_hash(transaction_hash)
|
191
|
+
response = BankingStatementResponse.new
|
192
|
+
|
193
|
+
response.transaction_identifier = transaction_hash['TRNUID']
|
194
|
+
response.status = OFX::Status.from_ofx_102_hash(transaction_hash['STATUS'])
|
195
|
+
|
196
|
+
response_hash = transaction_hash['STMTRS']
|
197
|
+
return unless response_hash
|
198
|
+
|
199
|
+
response.default_currency = response_hash['CURDEF']
|
200
|
+
response.account = BankingAccount.from_ofx_102_hash(response_hash['BANKACCTFROM'])
|
201
|
+
|
202
|
+
response.marketing_information = response_hash['MKTGINFO']
|
203
|
+
|
204
|
+
response.ledger_balance = Balance.from_ofx_102_hash(response_hash['LEDGERBAL']) if response_hash['LEDGERBAL']
|
205
|
+
response.available_balance = Balance.from_ofx_102_hash(response_hash['AVAILBAL']) if response_hash['AVAILBAL']
|
206
|
+
|
207
|
+
transaction_list_hash = response_hash['BANKTRANLIST']
|
208
|
+
if (transaction_list_hash)
|
209
|
+
response.transaction_range = transaction_list_hash['DTSTART'].to_datetime..transaction_list_hash['DTEND'].to_datetime
|
210
|
+
|
211
|
+
response.transactions = []
|
212
|
+
transactions = transaction_list_hash['STMTTRN'] if transaction_list_hash['STMTTRN'].kind_of?(Array)
|
213
|
+
transactions = [transaction_list_hash['STMTTRN']] if transaction_list_hash['STMTTRN'].kind_of?(Hash)
|
214
|
+
transactions = [] unless transactions
|
215
|
+
|
216
|
+
transactions.each do |transaction_hash|
|
217
|
+
transaction = Transaction.new
|
218
|
+
|
219
|
+
transaction.transaction_type = Transaction.ofx_102_transaction_type_name_to_transaction_type(transaction_hash['TRNTYPE'])
|
220
|
+
transaction.date_posted = transaction_hash['DTPOSTED'].to_datetime if transaction_hash['DTPOSTED']
|
221
|
+
transaction.date_initiated = transaction_hash['DTUSER'].to_datetime if transaction_hash['DTUSER']
|
222
|
+
transaction.date_available = transaction_hash['DTAVAIL'].to_datetime if transaction_hash['DTAVAIL']
|
223
|
+
|
224
|
+
transaction.amount = transaction_hash['TRNAMT'].to_d
|
225
|
+
transaction.currency = transaction_hash['CURRENCY'] || transaction_hash['ORIGCURRENCY'] || response.default_currency
|
226
|
+
|
227
|
+
transaction.financial_institution_transaction_identifier = transaction_hash['FITID']
|
228
|
+
transaction.corrected_financial_institution_transaction_identifier = transaction_hash['CORRECTFITID']
|
229
|
+
transaction.correction_action = case transaction_hash['CORRECT_ACTION']
|
230
|
+
when 'REPLACE' then :replace
|
231
|
+
when 'DELETE' then :delete
|
232
|
+
end if transaction_hash['CORRECT_ACTION']
|
233
|
+
transaction.server_transaction_identifier = transaction_hash['SRVRTID']
|
234
|
+
transaction.check_number = transaction_hash['CHECKNUM']
|
235
|
+
transaction.reference_number = transaction_hash['REFNUM']
|
236
|
+
|
237
|
+
transaction.standard_industrial_code = transaction_hash['SIC']
|
238
|
+
|
239
|
+
transaction.payee_identifier = transaction_hash['PAYEEID']
|
240
|
+
if transaction_hash['PAYEE']
|
241
|
+
raise NotImplementedError
|
242
|
+
else
|
243
|
+
transaction.payee = transaction_hash['NAME']
|
244
|
+
end
|
245
|
+
|
246
|
+
if (transaction_hash['BANKACCTTO'])
|
247
|
+
transaction.transfer_destination_account = BankingAccount.from_ofx_102_hash(transaction_hash['BANKACCTTO'])
|
248
|
+
elsif (transaction_hash['CCACCTTO'])
|
249
|
+
transaction.transfer_destination_account = CreditCardAccount.from_ofx_102_hash(transaction_hash['CCACCTTO'])
|
250
|
+
end
|
251
|
+
|
252
|
+
transaction.memo = transaction_hash['MEMO']
|
253
|
+
|
254
|
+
response.transactions << transaction
|
255
|
+
end
|
256
|
+
end
|
257
|
+
|
258
|
+
response
|
259
|
+
end
|
260
|
+
end
|
261
|
+
end
|