ofx 0.3.4 → 0.3.6
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.
- checksums.yaml +4 -4
- data/README.rdoc +2 -2
- data/lib/ofx/parser/ofx102.rb +10 -8
- data/lib/ofx/parser.rb +1 -1
- data/lib/ofx/version.rb +1 -1
- data/spec/ofx/ofx102_spec.rb +1 -1
- data/spec/ofx/ofx103_spec.rb +1 -1
- data/spec/ofx/ofx_parser_spec.rb +21 -8
- data/spec/ofx/transaction_spec.rb +53 -34
- data/spec/spec_helper.rb +5 -0
- metadata +10 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 98b2accf4fa4b1b9d0d8168e4518140484b69be77dfc114d5924eea1cf6eb912
|
4
|
+
data.tar.gz: c7eb6a605614095ac31ffcc840965a965146f803453652a37d1d2855e2dbc5e4
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: daf84f358d5810cfa9916dcce97bedb6297718f1db96e9bf347a5fef041c35eafa4e7934e0509a0c0133199ef678713ebba377afdde3f8172f523808abfb1ea4
|
7
|
+
data.tar.gz: 3bee29bfb6338c36842e5b08321944c3b4c668e607b3c980b2acba9dfa530941f17157ca0ca8921cb6479e380a33c4145a309e5f5cdf482a8147c06fa98627c2
|
data/README.rdoc
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
= OFX
|
2
2
|
|
3
|
-
{<img src="https://badge.fury.io/rb/ofx.
|
4
|
-
{<img src="https://
|
3
|
+
{<img src="https://badge.fury.io/rb/ofx.svg" alt="Gem Version" />}[https://badge.fury.io/rb/ofx]
|
4
|
+
{<img src="https://github.com/annacruz/ofx/actions/workflows/config.yml/badge.svg" alt="Build Status" />}[https://github.com/annacruz/ofx/actions]
|
5
5
|
|
6
6
|
A simple OFX (Open Financial Exchange) parser built on top of Nokogiri. Currently supports both OFX 1.0.2 and 2.1.1.
|
7
7
|
|
data/lib/ofx/parser/ofx102.rb
CHANGED
@@ -14,7 +14,7 @@ module OFX
|
|
14
14
|
|
15
15
|
TRANSACTION_TYPES = %w[
|
16
16
|
ATM CASH CHECK CREDIT DEBIT DEP DIRECTDEBIT DIRECTDEP DIV
|
17
|
-
FEE INT OTHER PAYMENT POS REPEATPMT SRVCHG XFER
|
17
|
+
FEE INT OTHER PAYMENT POS REPEATPMT SRVCHG XFER IN OUT
|
18
18
|
].each_with_object({}) do |tran_type, hash|
|
19
19
|
hash[tran_type] = tran_type.downcase.to_sym
|
20
20
|
end
|
@@ -23,7 +23,7 @@ module OFX
|
|
23
23
|
'INFO' => :info,
|
24
24
|
'WARN' => :warn,
|
25
25
|
'ERROR' => :error
|
26
|
-
}.
|
26
|
+
}.freeze
|
27
27
|
|
28
28
|
attr_reader :headers, :body, :html
|
29
29
|
|
@@ -52,7 +52,7 @@ module OFX
|
|
52
52
|
|
53
53
|
def self.parse_headers(header_text)
|
54
54
|
# Change single CR's to LF's to avoid issues with some banks
|
55
|
-
header_text.gsub!(/\r(?!\n)/,
|
55
|
+
header_text.gsub!(/\r(?!\n)/, "\n")
|
56
56
|
|
57
57
|
# Parse headers. When value is NONE, convert it to nil.
|
58
58
|
headers = header_text.to_enum(:each_line).each_with_object({}) do |line, memo|
|
@@ -134,7 +134,7 @@ module OFX
|
|
134
134
|
check_number: element.search('checknum').inner_text,
|
135
135
|
ref_number: element.search('refnum').inner_text,
|
136
136
|
posted_at: build_date(element.search('dtposted').inner_text),
|
137
|
-
occurred_at
|
137
|
+
occurred_at: occurred_at,
|
138
138
|
type: build_type(element),
|
139
139
|
sic: element.search('sic').inner_text
|
140
140
|
})
|
@@ -164,7 +164,7 @@ module OFX
|
|
164
164
|
offset = '+0000'
|
165
165
|
end
|
166
166
|
|
167
|
-
date <<
|
167
|
+
date << " #{offset}"
|
168
168
|
|
169
169
|
Time.parse(date)
|
170
170
|
end
|
@@ -178,9 +178,9 @@ module OFX
|
|
178
178
|
end
|
179
179
|
|
180
180
|
OFX::Balance.new({
|
181
|
-
amount
|
181
|
+
amount: amount,
|
182
182
|
amount_in_pennies: (amount * 100).to_i,
|
183
|
-
posted_at:
|
183
|
+
posted_at: posted_at
|
184
184
|
})
|
185
185
|
end
|
186
186
|
|
@@ -189,7 +189,7 @@ module OFX
|
|
189
189
|
amount = to_decimal(node.search('availbal > balamt').inner_text)
|
190
190
|
|
191
191
|
OFX::Balance.new({
|
192
|
-
amount
|
192
|
+
amount: amount,
|
193
193
|
amount_in_pennies: (amount * 100).to_i,
|
194
194
|
posted_at: build_date(node.search('availbal > dtasof').inner_text)
|
195
195
|
})
|
@@ -198,6 +198,8 @@ module OFX
|
|
198
198
|
|
199
199
|
def to_decimal(amount)
|
200
200
|
BigDecimal(amount.to_s.gsub(',', '.'))
|
201
|
+
rescue ArgumentError
|
202
|
+
BigDecimal('0.0')
|
201
203
|
end
|
202
204
|
end
|
203
205
|
end
|
data/lib/ofx/parser.rb
CHANGED
data/lib/ofx/version.rb
CHANGED
data/spec/ofx/ofx102_spec.rb
CHANGED
@@ -39,7 +39,7 @@ describe OFX::Parser::OFX102 do
|
|
39
39
|
it "should know about all transaction types" do
|
40
40
|
valid_types = [
|
41
41
|
'CREDIT', 'DEBIT', 'INT', 'DIV', 'FEE', 'SRVCHG', 'DEP', 'ATM', 'POS', 'XFER',
|
42
|
-
'CHECK', 'PAYMENT', 'CASH', 'DIRECTDEP', 'DIRECTDEBIT', 'REPEATPMT', 'OTHER'
|
42
|
+
'CHECK', 'PAYMENT', 'CASH', 'DIRECTDEP', 'DIRECTDEBIT', 'REPEATPMT', 'OTHER', 'IN', 'OUT'
|
43
43
|
]
|
44
44
|
valid_types.sort.should == OFX::Parser::OFX102::TRANSACTION_TYPES.keys.sort
|
45
45
|
|
data/spec/ofx/ofx103_spec.rb
CHANGED
@@ -39,7 +39,7 @@ describe OFX::Parser::OFX103 do
|
|
39
39
|
it "should know about all transaction types" do
|
40
40
|
valid_types = [
|
41
41
|
'CREDIT', 'DEBIT', 'INT', 'DIV', 'FEE', 'SRVCHG', 'DEP', 'ATM', 'POS', 'XFER',
|
42
|
-
'CHECK', 'PAYMENT', 'CASH', 'DIRECTDEP', 'DIRECTDEBIT', 'REPEATPMT', 'OTHER'
|
42
|
+
'CHECK', 'PAYMENT', 'CASH', 'DIRECTDEP', 'DIRECTDEBIT', 'REPEATPMT', 'OTHER', 'IN', 'OUT'
|
43
43
|
]
|
44
44
|
valid_types.sort.should == OFX::Parser::OFX103::TRANSACTION_TYPES.keys.sort
|
45
45
|
|
data/spec/ofx/ofx_parser_spec.rb
CHANGED
@@ -47,8 +47,16 @@ describe OFX::Parser do
|
|
47
47
|
}.should raise_error(OFX::UnsupportedFileError)
|
48
48
|
end
|
49
49
|
|
50
|
-
it "
|
51
|
-
OFX::Parser::
|
50
|
+
it "uses 102 parser to parse version 100 ofx files" do
|
51
|
+
expect(OFX::Parser::OFX102).to receive(:new).and_return('ofx-102-parser')
|
52
|
+
|
53
|
+
ofx = OFX::Parser::Base.new(ofx_2_example('100'))
|
54
|
+
expect(ofx.parser).to eql 'ofx-102-parser'
|
55
|
+
end
|
56
|
+
|
57
|
+
it "uses 211 parser to parse version 200 ofx files" do
|
58
|
+
expect(OFX::Parser::OFX211).to receive(:new).and_return('ofx-211-parser')
|
59
|
+
|
52
60
|
ofx = OFX::Parser::Base.new(ofx_2_example('200'))
|
53
61
|
ofx.parser.should == 'ofx-211-parser'
|
54
62
|
end
|
@@ -59,6 +67,13 @@ describe OFX::Parser do
|
|
59
67
|
ofx.parser.should == 'ofx-211-parser'
|
60
68
|
end
|
61
69
|
|
70
|
+
it "uses 211 parser to parse version 220 ofx files" do
|
71
|
+
expect(OFX::Parser::OFX211).to receive(:new).and_return('ofx-211-parser')
|
72
|
+
|
73
|
+
ofx = OFX::Parser::Base.new(ofx_2_example('220'))
|
74
|
+
expect(ofx.parser).to eql 'ofx-211-parser'
|
75
|
+
end
|
76
|
+
|
62
77
|
describe "headers" do
|
63
78
|
it "should have OFXHEADER" do
|
64
79
|
@ofx.headers["OFXHEADER"].should == "100"
|
@@ -101,17 +116,15 @@ describe OFX::Parser do
|
|
101
116
|
end
|
102
117
|
|
103
118
|
it "should parse headers with CR and without LF" do
|
119
|
+
header = %{OFXHEADER:100\rDATA:OFXSGML\rVERSION:102\rSECURITY:NONE\rENCODING:USASCII\rCHARSET:1252\rCOMPRESSION:NONE\rOLDFILEUID:NONE\rNEWFILEUID:NONE\r}
|
120
|
+
body = open("spec/fixtures/sample.ofx").read.split(/<OFX>/, 2)[1]
|
121
|
+
ofx_with_carriage_return = header + "<OFX>" + body
|
122
|
+
|
104
123
|
@ofx = OFX::Parser::Base.new(ofx_with_carriage_return)
|
105
124
|
@ofx.headers.size.should be(9)
|
106
125
|
end
|
107
126
|
end
|
108
127
|
|
109
|
-
def ofx_with_carriage_return
|
110
|
-
header = %{OFXHEADER:100\rDATA:OFXSGML\rVERSION:102\rSECURITY:NONE\rENCODING:USASCII\rCHARSET:1252\rCOMPRESSION:NONE\rOLDFILEUID:NONE\rNEWFILEUID:NONE\r}
|
111
|
-
body = open("spec/fixtures/sample.ofx").read.split(/<OFX>/, 2)[1]
|
112
|
-
header + "<OFX>" + body
|
113
|
-
end
|
114
|
-
|
115
128
|
def ofx_2_example(version)
|
116
129
|
<<-EndOfx
|
117
130
|
<?xml version="1.0" encoding="US-ASCII"?>
|
@@ -13,43 +13,43 @@ describe OFX::Transaction do
|
|
13
13
|
end
|
14
14
|
|
15
15
|
it "should set amount" do
|
16
|
-
@transaction.amount.
|
16
|
+
expect(@transaction.amount).to eql BigDecimal('-35.34')
|
17
17
|
end
|
18
18
|
|
19
19
|
it "should cast amount to BigDecimal" do
|
20
|
-
@transaction.amount.class.
|
20
|
+
expect(@transaction.amount.class).to be BigDecimal
|
21
21
|
end
|
22
22
|
|
23
23
|
it "should set amount in pennies" do
|
24
|
-
@transaction.amount_in_pennies.
|
24
|
+
expect(@transaction.amount_in_pennies).to eql -3534
|
25
25
|
end
|
26
26
|
|
27
27
|
it "should set fit id" do
|
28
|
-
@transaction.fit_id.
|
28
|
+
expect(@transaction.fit_id).to eql "200910091"
|
29
29
|
end
|
30
30
|
|
31
31
|
it "should set memo" do
|
32
|
-
@transaction.memo.
|
32
|
+
expect(@transaction.memo).to eql "COMPRA VISA ELECTRON"
|
33
33
|
end
|
34
34
|
|
35
35
|
it "should set check number" do
|
36
|
-
@transaction.check_number.
|
36
|
+
expect(@transaction.check_number).to eql "0001223"
|
37
37
|
end
|
38
38
|
|
39
39
|
it "should have date" do
|
40
|
-
@transaction.posted_at.
|
40
|
+
expect(@transaction.posted_at).to eql Time.parse("2009-10-09 08:00:00 +0000")
|
41
41
|
end
|
42
42
|
|
43
43
|
it 'should have user date' do
|
44
|
-
@transaction.occurred_at.
|
44
|
+
expect(@transaction.occurred_at).to eql Time.parse("2009-09-09 08:00:00 +0000")
|
45
45
|
end
|
46
46
|
|
47
47
|
it "should have type" do
|
48
|
-
@transaction.type.
|
48
|
+
expect(@transaction.type).to eql :debit
|
49
49
|
end
|
50
50
|
|
51
51
|
it "should have sic" do
|
52
|
-
@transaction.sic.
|
52
|
+
expect(@transaction.sic).to eql '5072'
|
53
53
|
end
|
54
54
|
end
|
55
55
|
|
@@ -59,39 +59,39 @@ describe OFX::Transaction do
|
|
59
59
|
end
|
60
60
|
|
61
61
|
it "should set amount" do
|
62
|
-
@transaction.amount.
|
62
|
+
expect(@transaction.amount).to eql BigDecimal('60.39')
|
63
63
|
end
|
64
64
|
|
65
65
|
it "should set amount in pennies" do
|
66
|
-
@transaction.amount_in_pennies.
|
66
|
+
expect(@transaction.amount_in_pennies).to eql 6039
|
67
67
|
end
|
68
68
|
|
69
69
|
it "should set fit id" do
|
70
|
-
@transaction.fit_id.
|
70
|
+
expect(@transaction.fit_id).to eql "200910162"
|
71
71
|
end
|
72
72
|
|
73
73
|
it "should set memo" do
|
74
|
-
@transaction.memo.
|
74
|
+
expect(@transaction.memo).to eql "DEPOSITO POUP.CORRENTE"
|
75
75
|
end
|
76
76
|
|
77
77
|
it "should set check number" do
|
78
|
-
@transaction.check_number.
|
78
|
+
expect(@transaction.check_number).to eql "0880136"
|
79
79
|
end
|
80
80
|
|
81
81
|
it "should have date" do
|
82
|
-
@transaction.posted_at.
|
82
|
+
expect(@transaction.posted_at).to eql Time.parse("2009-10-16 08:00:00 +0000")
|
83
83
|
end
|
84
84
|
|
85
85
|
it "should have user date" do
|
86
|
-
@transaction.occurred_at.
|
86
|
+
expect(@transaction.occurred_at).to eql Time.parse("2009-09-16 08:00:00 +0000")
|
87
87
|
end
|
88
88
|
|
89
89
|
it "should have type" do
|
90
|
-
@transaction.type.
|
90
|
+
expect(@transaction.type).to eql :credit
|
91
91
|
end
|
92
92
|
|
93
93
|
it "should have empty sic" do
|
94
|
-
@transaction.sic.
|
94
|
+
expect(@transaction.sic).to eql ''
|
95
95
|
end
|
96
96
|
end
|
97
97
|
|
@@ -101,27 +101,27 @@ describe OFX::Transaction do
|
|
101
101
|
end
|
102
102
|
|
103
103
|
it "should set payee" do
|
104
|
-
@transaction.payee.
|
104
|
+
expect(@transaction.payee).to eql "Pagto conta telefone"
|
105
105
|
end
|
106
106
|
|
107
107
|
it "should set check number" do
|
108
|
-
@transaction.check_number.
|
108
|
+
expect(@transaction.check_number).to eql "000000101901"
|
109
109
|
end
|
110
110
|
|
111
111
|
it "should have date" do
|
112
|
-
@transaction.posted_at.
|
112
|
+
expect(@transaction.posted_at).to eql Time.parse("2009-10-19 12:00:00 -0300")
|
113
113
|
end
|
114
114
|
|
115
115
|
it "should have user date" do
|
116
|
-
@transaction.occurred_at.
|
116
|
+
expect(@transaction.occurred_at).to eql Time.parse("2009-10-17 12:00:00 -0300")
|
117
117
|
end
|
118
118
|
|
119
119
|
it "should have type" do
|
120
|
-
@transaction.type.
|
120
|
+
expect(@transaction.type).to eql :other
|
121
121
|
end
|
122
122
|
|
123
123
|
it "should have reference number" do
|
124
|
-
@transaction.ref_number.
|
124
|
+
expect(@transaction.ref_number).to eql "101.901"
|
125
125
|
end
|
126
126
|
end
|
127
127
|
|
@@ -131,7 +131,7 @@ describe OFX::Transaction do
|
|
131
131
|
end
|
132
132
|
|
133
133
|
it "should set name" do
|
134
|
-
@transaction.name.
|
134
|
+
expect(@transaction.name).to eql "Pagto conta telefone"
|
135
135
|
end
|
136
136
|
end
|
137
137
|
|
@@ -144,22 +144,22 @@ describe OFX::Transaction do
|
|
144
144
|
|
145
145
|
it "should return dep" do
|
146
146
|
@transaction = @account.transactions[9]
|
147
|
-
@transaction.type.
|
147
|
+
expect(@transaction.type).to eql :dep
|
148
148
|
end
|
149
149
|
|
150
150
|
it "should return xfer" do
|
151
151
|
@transaction = @account.transactions[18]
|
152
|
-
@transaction.type.
|
152
|
+
expect(@transaction.type).to eql :xfer
|
153
153
|
end
|
154
154
|
|
155
155
|
it "should return cash" do
|
156
156
|
@transaction = @account.transactions[45]
|
157
|
-
@transaction.type.
|
157
|
+
expect(@transaction.type).to eql :cash
|
158
158
|
end
|
159
159
|
|
160
160
|
it "should return check" do
|
161
161
|
@transaction = @account.transactions[0]
|
162
|
-
@transaction.type.
|
162
|
+
expect(@transaction.type).to eql :check
|
163
163
|
end
|
164
164
|
end
|
165
165
|
|
@@ -176,11 +176,11 @@ describe OFX::Transaction do
|
|
176
176
|
end
|
177
177
|
|
178
178
|
it "should set amount" do
|
179
|
-
@transaction.amount.
|
179
|
+
expect(@transaction.amount).to eql BigDecimal('-11.76')
|
180
180
|
end
|
181
181
|
|
182
182
|
it "should set amount in pennies" do
|
183
|
-
@transaction.amount_in_pennies.
|
183
|
+
expect(@transaction.amount_in_pennies).to eql -1176
|
184
184
|
end
|
185
185
|
end
|
186
186
|
|
@@ -190,12 +190,31 @@ describe OFX::Transaction do
|
|
190
190
|
end
|
191
191
|
|
192
192
|
it "should set amount" do
|
193
|
-
@transaction.amount.
|
193
|
+
expect(@transaction.amount).to eql BigDecimal('47.01')
|
194
194
|
end
|
195
195
|
|
196
196
|
it "should set amount in pennies" do
|
197
|
-
@transaction.amount_in_pennies.
|
197
|
+
expect(@transaction.amount_in_pennies).to eql 4701
|
198
198
|
end
|
199
199
|
end
|
200
200
|
end
|
201
|
+
|
202
|
+
context "invalid decimal values" do
|
203
|
+
before do
|
204
|
+
@ofx = OFX::Parser::Base.new("spec/fixtures/cef_malformed_decimal.ofx")
|
205
|
+
@parser = @ofx.parser
|
206
|
+
end
|
207
|
+
|
208
|
+
it "should not raise error" do
|
209
|
+
expect { @parser.account.transactions }.to_not raise_error
|
210
|
+
end
|
211
|
+
|
212
|
+
it "should return zero in amount" do
|
213
|
+
expect(@parser.account.transactions[0].amount).to eql BigDecimal('0.0')
|
214
|
+
end
|
215
|
+
|
216
|
+
it "should return zero in amount_in_pennies" do
|
217
|
+
expect(@parser.account.transactions[0].amount_in_pennies).to eql 0
|
218
|
+
end
|
219
|
+
end
|
201
220
|
end
|
data/spec/spec_helper.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
require "ofx"
|
2
|
+
require "byebug"
|
2
3
|
|
3
4
|
RSpec::Matchers.define :have_key do |key|
|
4
5
|
match do |hash|
|
@@ -7,3 +8,7 @@ RSpec::Matchers.define :have_key do |key|
|
|
7
8
|
hash.keys.include?(key)
|
8
9
|
end
|
9
10
|
end
|
11
|
+
|
12
|
+
RSpec.configure do |c|
|
13
|
+
c.filter_run_when_matching :focus
|
14
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ofx
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.3.
|
4
|
+
version: 0.3.6
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Nando Vieira
|
@@ -9,22 +9,28 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date:
|
12
|
+
date: 2025-06-12 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: nokogiri
|
16
16
|
requirement: !ruby/object:Gem::Requirement
|
17
17
|
requirements:
|
18
|
-
- - "
|
18
|
+
- - ">="
|
19
19
|
- !ruby/object:Gem::Version
|
20
20
|
version: 1.13.1
|
21
|
+
- - "<"
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: 1.16.0
|
21
24
|
type: :runtime
|
22
25
|
prerelease: false
|
23
26
|
version_requirements: !ruby/object:Gem::Requirement
|
24
27
|
requirements:
|
25
|
-
- - "
|
28
|
+
- - ">="
|
26
29
|
- !ruby/object:Gem::Version
|
27
30
|
version: 1.13.1
|
31
|
+
- - "<"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 1.16.0
|
28
34
|
- !ruby/object:Gem::Dependency
|
29
35
|
name: byebug
|
30
36
|
requirement: !ruby/object:Gem::Requirement
|