ofx 0.2.8 → 0.2.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/Gemfile.lock +1 -1
- data/lib/ofx.rb +3 -0
- data/lib/ofx/parser.rb +24 -27
- data/lib/ofx/parser/ofx102.rb +62 -61
- data/lib/ofx/version.rb +1 -1
- data/ofx.gemspec +0 -2
- data/spec/fixtures/bb.ofx +8 -0
- data/spec/ofx/transaction_spec.rb +8 -3
- metadata +4 -4
data/Gemfile.lock
CHANGED
data/lib/ofx.rb
CHANGED
data/lib/ofx/parser.rb
CHANGED
@@ -1,6 +1,3 @@
|
|
1
|
-
require "iconv"
|
2
|
-
require "kconv"
|
3
|
-
|
4
1
|
module OFX
|
5
2
|
module Parser
|
6
3
|
class Base
|
@@ -42,35 +39,35 @@ module OFX
|
|
42
39
|
end
|
43
40
|
|
44
41
|
private
|
45
|
-
|
46
|
-
|
47
|
-
|
42
|
+
def prepare(content)
|
43
|
+
# Split headers & body
|
44
|
+
headers, body = content.dup.split(/<OFX>/, 2)
|
48
45
|
|
49
|
-
|
50
|
-
|
46
|
+
# Change single CR's to LF's to avoid issues with some banks
|
47
|
+
headers.gsub!(/\r(?!\n)/, "\n")
|
51
48
|
|
52
|
-
|
49
|
+
raise OFX::UnsupportedFileError unless body
|
53
50
|
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
51
|
+
# Parse headers. When value is NONE, convert it to nil.
|
52
|
+
headers = headers.to_enum(:each_line).inject({}) do |memo, line|
|
53
|
+
_, key, value = *line.match(/^(.*?):(.*?)(\r?\n)*$/)
|
54
|
+
memo[key] = value == "NONE" ? nil : value
|
55
|
+
memo
|
56
|
+
end
|
60
57
|
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
58
|
+
# Replace body tags to parse it with Nokogiri
|
59
|
+
body.gsub!(/>\s+</m, '><')
|
60
|
+
body.gsub!(/\s+</m, '<')
|
61
|
+
body.gsub!(/>\s+/m, '>')
|
62
|
+
body.gsub!(/<(\w+?)>([^<]+)/m, '<\1>\2</\1>')
|
66
63
|
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
64
|
+
[headers, body]
|
65
|
+
end
|
66
|
+
|
67
|
+
def convert_to_utf8(string)
|
68
|
+
return string if Kconv.isutf8(string)
|
69
|
+
Iconv.conv('UTF-8', 'LATIN1//IGNORE', string)
|
70
|
+
end
|
74
71
|
end
|
75
72
|
end
|
76
73
|
end
|
data/lib/ofx/parser/ofx102.rb
CHANGED
@@ -4,92 +4,93 @@ module OFX
|
|
4
4
|
module Parser
|
5
5
|
class OFX102
|
6
6
|
VERSION = "1.0.2"
|
7
|
-
|
7
|
+
|
8
8
|
ACCOUNT_TYPES = {
|
9
9
|
"CHECKING" => :checking
|
10
10
|
}
|
11
|
-
|
11
|
+
|
12
12
|
TRANSACTION_TYPES = {
|
13
13
|
"CREDIT" => :credit,
|
14
14
|
"DEBIT" => :debit,
|
15
15
|
"OTHER" => :other,
|
16
16
|
"DEP" => :dep,
|
17
17
|
"XFER" => :xfer,
|
18
|
-
"CASH" => :cash
|
18
|
+
"CASH" => :cash,
|
19
|
+
"CHECK" => :check
|
19
20
|
}
|
20
|
-
|
21
|
+
|
21
22
|
attr_reader :headers
|
22
23
|
attr_reader :body
|
23
24
|
attr_reader :html
|
24
|
-
|
25
|
+
|
25
26
|
def initialize(options = {})
|
26
27
|
@headers = options[:headers]
|
27
28
|
@body = options[:body]
|
28
29
|
@html = Nokogiri::HTML.parse(body)
|
29
30
|
end
|
30
|
-
|
31
|
+
|
31
32
|
def account
|
32
33
|
@account ||= build_account
|
33
34
|
end
|
34
|
-
|
35
|
+
|
35
36
|
private
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
def build_transactions
|
48
|
-
html.search("banktranlist > stmttrn").collect do |element|
|
49
|
-
build_transaction(element)
|
50
|
-
end
|
51
|
-
end
|
52
|
-
|
53
|
-
def build_transaction(element)
|
54
|
-
OFX::Transaction.new({
|
55
|
-
:amount => build_amount(element),
|
56
|
-
:amount_in_pennies => (build_amount(element) * 100).to_i,
|
57
|
-
:fit_id => element.search("fitid").inner_text,
|
58
|
-
:memo => element.search("memo").inner_text,
|
59
|
-
:payee => element.search("payee").inner_text,
|
60
|
-
:check_number => element.search("checknum").inner_text,
|
61
|
-
:ref_number => element.search("refnum").inner_text,
|
62
|
-
:posted_at => build_date(element.search("dtposted").inner_text),
|
63
|
-
:type => build_type(element)
|
64
|
-
})
|
65
|
-
end
|
37
|
+
def build_account
|
38
|
+
OFX::Account.new({
|
39
|
+
:bank_id => html.search("bankacctfrom > bankid").inner_text,
|
40
|
+
:id => html.search("bankacctfrom > acctid").inner_text,
|
41
|
+
:type => ACCOUNT_TYPES[html.search("bankacctfrom > accttype").inner_text],
|
42
|
+
:transactions => build_transactions,
|
43
|
+
:balance => build_balance,
|
44
|
+
:currency => html.search("bankmsgsrsv1 > stmttrnrs > stmtrs > curdef").inner_text
|
45
|
+
})
|
46
|
+
end
|
66
47
|
|
67
|
-
|
68
|
-
|
48
|
+
def build_transactions
|
49
|
+
html.search("banktranlist > stmttrn").collect do |element|
|
50
|
+
build_transaction(element)
|
69
51
|
end
|
52
|
+
end
|
70
53
|
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
54
|
+
def build_transaction(element)
|
55
|
+
OFX::Transaction.new({
|
56
|
+
:amount => build_amount(element),
|
57
|
+
:amount_in_pennies => (build_amount(element) * 100).to_i,
|
58
|
+
:fit_id => element.search("fitid").inner_text,
|
59
|
+
:memo => element.search("memo").inner_text,
|
60
|
+
:payee => element.search("payee").inner_text,
|
61
|
+
:check_number => element.search("checknum").inner_text,
|
62
|
+
:ref_number => element.search("refnum").inner_text,
|
63
|
+
:posted_at => build_date(element.search("dtposted").inner_text),
|
64
|
+
:type => build_type(element)
|
65
|
+
})
|
66
|
+
end
|
67
|
+
|
68
|
+
def build_type(element)
|
69
|
+
TRANSACTION_TYPES[element.search("trntype").inner_text]
|
70
|
+
end
|
71
|
+
|
72
|
+
def build_amount(element)
|
73
|
+
BigDecimal.new(element.search("trnamt").inner_text)
|
74
|
+
end
|
75
|
+
|
76
|
+
def build_date(date)
|
77
|
+
_, year, month, day, hour, minutes, seconds = *date.match(/(\d{4})(\d{2})(\d{2})(?:(\d{2})(\d{2})(\d{2}))?/)
|
78
|
+
|
79
|
+
date = "#{year}-#{month}-#{day} "
|
80
|
+
date << "#{hour}:#{minutes}:#{seconds}" if hour && minutes && seconds
|
81
|
+
|
82
|
+
Time.parse(date)
|
83
|
+
end
|
84
|
+
|
85
|
+
def build_balance
|
86
|
+
amount = html.search("ledgerbal > balamt").inner_text.to_f
|
87
|
+
|
88
|
+
OFX::Balance.new({
|
89
|
+
:amount => amount,
|
90
|
+
:amount_in_pennies => (amount * 100).to_i,
|
91
|
+
:posted_at => build_date(html.search("ledgerbal > dtasof").inner_text)
|
92
|
+
})
|
93
|
+
end
|
93
94
|
end
|
94
95
|
end
|
95
96
|
end
|
data/lib/ofx/version.rb
CHANGED
data/ofx.gemspec
CHANGED
data/spec/fixtures/bb.ofx
CHANGED
@@ -40,6 +40,14 @@ NEWFILEUID:NONE
|
|
40
40
|
<BANKTRANLIST>
|
41
41
|
<DTSTART>20100930
|
42
42
|
<DTEND>20101025
|
43
|
+
<STMTTRN>
|
44
|
+
<TRNTYPE>CHECK
|
45
|
+
<DTPOSTED>20100826
|
46
|
+
<TRNAMT>-836.30
|
47
|
+
<FITID>20100826183630
|
48
|
+
<CHECKNUM>850076
|
49
|
+
<MEMO>CHEQUE COMPENSADO
|
50
|
+
</STMTTRN>
|
43
51
|
<STMTTRN>
|
44
52
|
<TRNTYPE>DEBIT
|
45
53
|
<DTPOSTED>20101001
|
@@ -114,20 +114,25 @@ describe OFX::Transaction do
|
|
114
114
|
end
|
115
115
|
|
116
116
|
it "should return dep" do
|
117
|
-
@transaction = @account.transactions[
|
117
|
+
@transaction = @account.transactions[9]
|
118
118
|
@transaction.type.should == :dep
|
119
119
|
end
|
120
120
|
|
121
121
|
it "should return xfer" do
|
122
|
-
@transaction = @account.transactions[
|
122
|
+
@transaction = @account.transactions[18]
|
123
123
|
@transaction.type.should == :xfer
|
124
124
|
end
|
125
125
|
|
126
126
|
it "should return cash" do
|
127
|
-
@transaction = @account.transactions[
|
127
|
+
@transaction = @account.transactions[45]
|
128
128
|
@transaction.type.should == :cash
|
129
129
|
end
|
130
130
|
|
131
|
+
it "should return check" do
|
132
|
+
@transaction = @account.transactions[0]
|
133
|
+
@transaction.type.should == :check
|
134
|
+
end
|
135
|
+
|
131
136
|
end
|
132
137
|
|
133
138
|
end
|
metadata
CHANGED
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
|
|
5
5
|
segments:
|
6
6
|
- 0
|
7
7
|
- 2
|
8
|
-
-
|
9
|
-
version: 0.2.
|
8
|
+
- 9
|
9
|
+
version: 0.2.9
|
10
10
|
platform: ruby
|
11
11
|
authors:
|
12
12
|
- Nando Vieira
|
@@ -14,7 +14,7 @@ autorequire:
|
|
14
14
|
bindir: bin
|
15
15
|
cert_chain: []
|
16
16
|
|
17
|
-
date: 2010-10
|
17
|
+
date: 2010-11-10 00:00:00 -02:00
|
18
18
|
default_executable:
|
19
19
|
dependencies:
|
20
20
|
- !ruby/object:Gem::Dependency
|
@@ -117,7 +117,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
117
117
|
version: "0"
|
118
118
|
requirements: []
|
119
119
|
|
120
|
-
rubyforge_project:
|
120
|
+
rubyforge_project:
|
121
121
|
rubygems_version: 1.3.7
|
122
122
|
signing_key:
|
123
123
|
specification_version: 3
|