ofx 0.3.5 → 0.3.8
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/account.rb +7 -3
- data/lib/ofx/balance.rb +4 -5
- data/lib/ofx/errors.rb +0 -2
- data/lib/ofx/foundation.rb +1 -4
- data/lib/ofx/parser/ofx102.rb +5 -3
- data/lib/ofx/parser/ofx211.rb +4 -8
- data/lib/ofx/parser.rb +15 -18
- data/lib/ofx/sign_on.rb +4 -3
- data/lib/ofx/statement.rb +7 -3
- data/lib/ofx/status.rb +4 -4
- data/lib/ofx/transaction.rb +12 -4
- data/lib/ofx/version.rb +1 -3
- data/lib/ofx.rb +0 -1
- data/spec/ofx/ofx102_spec.rb +1 -1
- data/spec/ofx/ofx_parser_spec.rb +53 -18
- data/spec/ofx/transaction_spec.rb +53 -34
- data/spec/spec_helper.rb +5 -0
- metadata +38 -6
- data/lib/ofx/parser/ofx103.rb +0 -7
- data/spec/ofx/ofx103_spec.rb +0 -50
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 390b59aff79c7a69d32b1344a63e6041c1131bbc98a45d8ac1557a172dea58bc
|
4
|
+
data.tar.gz: 2b3555e7617f797df7ecf2938a73e24e57638bec8f57ff5c5d317544bcd9bf78
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 960600058ef4b603ae95d35e0eadb4a60bbb8beb15b62164538f69e40b605e7dadeca048979b69ffce4608b642a826c34f59c5d5f04597cc815d38262b901c23
|
7
|
+
data.tar.gz: 106edb48e04d6882752085bcc569b03685506e6e4a27d4e3d4e629374060e9e374f89e0cbd8ee27f81ee335c84b15eccd37541a12844ae0da689ba6b29729ea3
|
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/account.rb
CHANGED
@@ -1,7 +1,11 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
1
|
module OFX
|
4
2
|
class Account < Foundation
|
5
|
-
attr_accessor :balance
|
3
|
+
attr_accessor :balance
|
4
|
+
attr_accessor :bank_id
|
5
|
+
attr_accessor :currency
|
6
|
+
attr_accessor :id
|
7
|
+
attr_accessor :transactions
|
8
|
+
attr_accessor :type
|
9
|
+
attr_accessor :available_balance
|
6
10
|
end
|
7
11
|
end
|
data/lib/ofx/balance.rb
CHANGED
data/lib/ofx/errors.rb
CHANGED
data/lib/ofx/foundation.rb
CHANGED
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
|
@@ -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|
|
@@ -178,7 +178,7 @@ 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
183
|
posted_at: posted_at
|
184
184
|
})
|
@@ -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/ofx211.rb
CHANGED
@@ -1,9 +1,7 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
1
|
module OFX
|
4
2
|
module Parser
|
5
3
|
class OFX211 < OFX102
|
6
|
-
VERSION =
|
4
|
+
VERSION = "2.1.1"
|
7
5
|
|
8
6
|
def self.parse_headers(header_text)
|
9
7
|
doc = Nokogiri::XML(header_text)
|
@@ -11,7 +9,7 @@ module OFX
|
|
11
9
|
# Nokogiri can't search for processing instructions, so we
|
12
10
|
# need to do this manually.
|
13
11
|
doc.children.each do |e|
|
14
|
-
if e.type == Nokogiri::XML::Node::PI_NODE && e.name ==
|
12
|
+
if e.type == Nokogiri::XML::Node::PI_NODE && e.name == "OFX"
|
15
13
|
# Getting the attributes from the element doesn't seem to
|
16
14
|
# work either.
|
17
15
|
return extract_headers(e.text)
|
@@ -21,14 +19,13 @@ module OFX
|
|
21
19
|
nil
|
22
20
|
end
|
23
21
|
|
22
|
+
private
|
24
23
|
def self.extract_headers(text)
|
25
24
|
headers = {}
|
26
25
|
text.split(/\s+/).each do |attr_text|
|
27
26
|
match = /(.+)="(.+)"/.match(attr_text)
|
28
27
|
next unless match
|
29
|
-
|
30
|
-
k = match[1]
|
31
|
-
v = match[2]
|
28
|
+
k, v = match[1], match[2]
|
32
29
|
headers[k] = v
|
33
30
|
end
|
34
31
|
headers
|
@@ -36,7 +33,6 @@ module OFX
|
|
36
33
|
|
37
34
|
def self.strip_quotes(s)
|
38
35
|
return unless s
|
39
|
-
|
40
36
|
s.sub(/^"(.*)"$/, '\1')
|
41
37
|
end
|
42
38
|
end
|
data/lib/ofx/parser.rb
CHANGED
@@ -1,9 +1,10 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
1
|
module OFX
|
4
2
|
module Parser
|
5
3
|
class Base
|
6
|
-
attr_reader :headers
|
4
|
+
attr_reader :headers
|
5
|
+
attr_reader :body
|
6
|
+
attr_reader :content
|
7
|
+
attr_reader :parser
|
7
8
|
|
8
9
|
def initialize(resource)
|
9
10
|
resource = open_resource(resource)
|
@@ -11,17 +12,15 @@ module OFX
|
|
11
12
|
begin
|
12
13
|
@content = convert_to_utf8(resource.read)
|
13
14
|
@headers, @body = prepare(content)
|
14
|
-
rescue
|
15
|
+
rescue
|
15
16
|
raise OFX::UnsupportedFileError
|
16
17
|
end
|
17
18
|
|
18
|
-
case headers[
|
19
|
-
when /102/
|
20
|
-
@parser = OFX102.new(headers
|
21
|
-
when /
|
22
|
-
@parser =
|
23
|
-
when /200|202|211|220/
|
24
|
-
@parser = OFX211.new(headers: headers, body: body)
|
19
|
+
case headers["VERSION"]
|
20
|
+
when /100|102|103/ then
|
21
|
+
@parser = OFX102.new(:headers => headers, :body => body)
|
22
|
+
when /200|202|211|220/ then
|
23
|
+
@parser = OFX211.new(:headers => headers, :body => body)
|
25
24
|
else
|
26
25
|
raise OFX::UnsupportedFileError
|
27
26
|
end
|
@@ -33,12 +32,11 @@ module OFX
|
|
33
32
|
else
|
34
33
|
open(resource)
|
35
34
|
end
|
36
|
-
rescue
|
35
|
+
rescue
|
37
36
|
StringIO.new(resource)
|
38
37
|
end
|
39
38
|
|
40
39
|
private
|
41
|
-
|
42
40
|
def prepare(content)
|
43
41
|
# split headers & body
|
44
42
|
header_text, body = content.dup.split(/<OFX>/, 2)
|
@@ -55,9 +53,9 @@ module OFX
|
|
55
53
|
end
|
56
54
|
|
57
55
|
# Replace body tags to parse it with Nokogiri
|
58
|
-
body.gsub!(/>\s+</m,
|
59
|
-
body.gsub!(/\s+</m,
|
60
|
-
body.gsub!(/>\s+/m,
|
56
|
+
body.gsub!(/>\s+</m, "><")
|
57
|
+
body.gsub!(/\s+</m, "<")
|
58
|
+
body.gsub!(/>\s+/m, ">")
|
61
59
|
body.gsub!(/<(\w+?)>([^<]+)/m, '<\1>\2</\1>')
|
62
60
|
|
63
61
|
[headers, body]
|
@@ -65,8 +63,7 @@ module OFX
|
|
65
63
|
|
66
64
|
def convert_to_utf8(string)
|
67
65
|
return string if Kconv.isutf8(string)
|
68
|
-
|
69
|
-
string.encode('UTF-8', 'ISO-8859-1')
|
66
|
+
string.encode("UTF-8", "ISO-8859-1")
|
70
67
|
end
|
71
68
|
end
|
72
69
|
end
|
data/lib/ofx/sign_on.rb
CHANGED
data/lib/ofx/statement.rb
CHANGED
@@ -1,7 +1,11 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
1
|
module OFX
|
4
2
|
class Statement < Foundation
|
5
|
-
attr_accessor :account
|
3
|
+
attr_accessor :account
|
4
|
+
attr_accessor :available_balance
|
5
|
+
attr_accessor :balance
|
6
|
+
attr_accessor :currency
|
7
|
+
attr_accessor :start_date
|
8
|
+
attr_accessor :end_date
|
9
|
+
attr_accessor :transactions
|
6
10
|
end
|
7
11
|
end
|
data/lib/ofx/status.rb
CHANGED
@@ -1,12 +1,12 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
1
|
module OFX
|
4
2
|
# Error Reporting Aggregate
|
5
3
|
class Status < Foundation
|
6
|
-
attr_accessor :code
|
4
|
+
attr_accessor :code # Error code
|
5
|
+
attr_accessor :severity # Severity of the error
|
6
|
+
attr_accessor :message # Textual explanation
|
7
7
|
|
8
8
|
def success?
|
9
|
-
code
|
9
|
+
code == 0
|
10
10
|
end
|
11
11
|
end
|
12
12
|
end
|
data/lib/ofx/transaction.rb
CHANGED
@@ -1,8 +1,16 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
1
|
module OFX
|
4
2
|
class Transaction < Foundation
|
5
|
-
attr_accessor :amount
|
6
|
-
|
3
|
+
attr_accessor :amount
|
4
|
+
attr_accessor :amount_in_pennies
|
5
|
+
attr_accessor :check_number
|
6
|
+
attr_accessor :fit_id
|
7
|
+
attr_accessor :memo
|
8
|
+
attr_accessor :name
|
9
|
+
attr_accessor :payee
|
10
|
+
attr_accessor :posted_at
|
11
|
+
attr_accessor :occurred_at
|
12
|
+
attr_accessor :ref_number
|
13
|
+
attr_accessor :type
|
14
|
+
attr_accessor :sic
|
7
15
|
end
|
8
16
|
end
|
data/lib/ofx/version.rb
CHANGED
data/lib/ofx.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/ofx_parser_spec.rb
CHANGED
@@ -1,6 +1,17 @@
|
|
1
1
|
require "spec_helper"
|
2
2
|
|
3
3
|
describe OFX::Parser do
|
4
|
+
def ofx_example_to(version)
|
5
|
+
<<~OFX_CONTENT
|
6
|
+
<?xml version="1.0" encoding="US-ASCII"?>
|
7
|
+
|
8
|
+
<?OFX OFXHEADER="200" VERSION="#{version}" SECURITY="NONE" OLDFILEUID="NONE" NEWFILEUID="NONE"?>"
|
9
|
+
|
10
|
+
<OFX>
|
11
|
+
</OFX>
|
12
|
+
OFX_CONTENT
|
13
|
+
end
|
14
|
+
|
4
15
|
before do
|
5
16
|
@ofx = OFX::Parser::Base.new("spec/fixtures/sample.ofx")
|
6
17
|
end
|
@@ -47,18 +58,53 @@ describe OFX::Parser do
|
|
47
58
|
}.should raise_error(OFX::UnsupportedFileError)
|
48
59
|
end
|
49
60
|
|
61
|
+
it "should use 102 parser to parse version 100 ofx files" do
|
62
|
+
expect(OFX::Parser::OFX102).to receive(:new).and_return('ofx-102-parser')
|
63
|
+
|
64
|
+
ofx = OFX::Parser::Base.new(ofx_example_to('100'))
|
65
|
+
expect(ofx.parser).to eql 'ofx-102-parser'
|
66
|
+
end
|
67
|
+
|
68
|
+
it "should use 102 parser to parse version 102 ofx files" do
|
69
|
+
expect(OFX::Parser::OFX102).to receive(:new).and_return('ofx-102-parser')
|
70
|
+
|
71
|
+
ofx = OFX::Parser::Base.new(ofx_example_to('102'))
|
72
|
+
expect(ofx.parser).to eql 'ofx-102-parser'
|
73
|
+
end
|
74
|
+
|
75
|
+
it "should use 102 parser to parse version 103 ofx files" do
|
76
|
+
expect(OFX::Parser::OFX102).to receive(:new).and_return('ofx-102-parser')
|
77
|
+
|
78
|
+
ofx = OFX::Parser::Base.new(ofx_example_to('103'))
|
79
|
+
expect(ofx.parser).to eql 'ofx-102-parser'
|
80
|
+
end
|
81
|
+
|
50
82
|
it "should use 211 parser to parse version 200 ofx files" do
|
51
|
-
OFX::Parser::OFX211.
|
52
|
-
|
83
|
+
expect(OFX::Parser::OFX211).to receive(:new).and_return('ofx-211-parser')
|
84
|
+
|
85
|
+
ofx = OFX::Parser::Base.new(ofx_example_to('200'))
|
53
86
|
ofx.parser.should == 'ofx-211-parser'
|
54
87
|
end
|
55
88
|
|
56
89
|
it "should use 211 parser to parse version 202 ofx files" do
|
57
90
|
OFX::Parser::OFX211.stub(:new).and_return('ofx-211-parser')
|
58
|
-
ofx = OFX::Parser::Base.new(
|
91
|
+
ofx = OFX::Parser::Base.new(ofx_example_to('202'))
|
59
92
|
ofx.parser.should == 'ofx-211-parser'
|
60
93
|
end
|
61
94
|
|
95
|
+
it "should use 211 parser to parse version 211 ofx files" do
|
96
|
+
OFX::Parser::OFX211.stub(:new).and_return('ofx-211-parser')
|
97
|
+
ofx = OFX::Parser::Base.new(ofx_example_to('211'))
|
98
|
+
ofx.parser.should == 'ofx-211-parser'
|
99
|
+
end
|
100
|
+
|
101
|
+
it "should use 211 parser to parse version 220 ofx files" do
|
102
|
+
expect(OFX::Parser::OFX211).to receive(:new).and_return('ofx-211-parser')
|
103
|
+
|
104
|
+
ofx = OFX::Parser::Base.new(ofx_example_to('220'))
|
105
|
+
expect(ofx.parser).to eql 'ofx-211-parser'
|
106
|
+
end
|
107
|
+
|
62
108
|
describe "headers" do
|
63
109
|
it "should have OFXHEADER" do
|
64
110
|
@ofx.headers["OFXHEADER"].should == "100"
|
@@ -101,23 +147,12 @@ describe OFX::Parser do
|
|
101
147
|
end
|
102
148
|
|
103
149
|
it "should parse headers with CR and without LF" do
|
150
|
+
header = %{OFXHEADER:100\rDATA:OFXSGML\rVERSION:102\rSECURITY:NONE\rENCODING:USASCII\rCHARSET:1252\rCOMPRESSION:NONE\rOLDFILEUID:NONE\rNEWFILEUID:NONE\r}
|
151
|
+
body = open("spec/fixtures/sample.ofx").read.split(/<OFX>/, 2)[1]
|
152
|
+
ofx_with_carriage_return = header + "<OFX>" + body
|
153
|
+
|
104
154
|
@ofx = OFX::Parser::Base.new(ofx_with_carriage_return)
|
105
155
|
@ofx.headers.size.should be(9)
|
106
156
|
end
|
107
157
|
end
|
108
|
-
|
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
|
-
def ofx_2_example(version)
|
116
|
-
<<-EndOfx
|
117
|
-
<?xml version="1.0" encoding="US-ASCII"?>
|
118
|
-
<?OFX OFXHEADER="200" VERSION="#{version}" SECURITY="NONE" OLDFILEUID="NONE" NEWFILEUID="NONE"?>"
|
119
|
-
<OFX>
|
120
|
-
</OFX>
|
121
|
-
EndOfx
|
122
|
-
end
|
123
158
|
end
|
@@ -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.8
|
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-19 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
|
@@ -67,6 +73,34 @@ dependencies:
|
|
67
73
|
- - "~>"
|
68
74
|
- !ruby/object:Gem::Version
|
69
75
|
version: '3.10'
|
76
|
+
- !ruby/object:Gem::Dependency
|
77
|
+
name: erb
|
78
|
+
requirement: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: 4.0.4
|
83
|
+
type: :runtime
|
84
|
+
prerelease: false
|
85
|
+
version_requirements: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - "~>"
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: 4.0.4
|
90
|
+
- !ruby/object:Gem::Dependency
|
91
|
+
name: stringio
|
92
|
+
requirement: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - "~>"
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: 3.1.7
|
97
|
+
type: :runtime
|
98
|
+
prerelease: false
|
99
|
+
version_requirements: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - "~>"
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: 3.1.7
|
70
104
|
description: |
|
71
105
|
A simple OFX (Open Financial Exchange) parser built on top of Nokogiri.
|
72
106
|
Currently supports OFX 102, 200 and 211.
|
@@ -92,7 +126,6 @@ files:
|
|
92
126
|
- lib/ofx/foundation.rb
|
93
127
|
- lib/ofx/parser.rb
|
94
128
|
- lib/ofx/parser/ofx102.rb
|
95
|
-
- lib/ofx/parser/ofx103.rb
|
96
129
|
- lib/ofx/parser/ofx211.rb
|
97
130
|
- lib/ofx/sign_on.rb
|
98
131
|
- lib/ofx/statement.rb
|
@@ -101,7 +134,6 @@ files:
|
|
101
134
|
- lib/ofx/version.rb
|
102
135
|
- spec/ofx/account_spec.rb
|
103
136
|
- spec/ofx/ofx102_spec.rb
|
104
|
-
- spec/ofx/ofx103_spec.rb
|
105
137
|
- spec/ofx/ofx211_spec.rb
|
106
138
|
- spec/ofx/ofx_parser_spec.rb
|
107
139
|
- spec/ofx/ofx_spec.rb
|
data/lib/ofx/parser/ofx103.rb
DELETED
data/spec/ofx/ofx103_spec.rb
DELETED
@@ -1,50 +0,0 @@
|
|
1
|
-
require "spec_helper"
|
2
|
-
|
3
|
-
describe OFX::Parser::OFX103 do
|
4
|
-
before do
|
5
|
-
@ofx = OFX::Parser::Base.new("spec/fixtures/v103.ofx")
|
6
|
-
@parser = @ofx.parser
|
7
|
-
end
|
8
|
-
|
9
|
-
it "should have a version" do
|
10
|
-
OFX::Parser::OFX103::VERSION.should == "1.0.3"
|
11
|
-
end
|
12
|
-
|
13
|
-
it "should set headers" do
|
14
|
-
@parser.headers.should == @ofx.headers
|
15
|
-
end
|
16
|
-
|
17
|
-
it "should trim trailing whitespace from headers" do
|
18
|
-
headers = OFX::Parser::OFX103.parse_headers("VERSION:103 ")
|
19
|
-
headers["VERSION"].should == "103"
|
20
|
-
end
|
21
|
-
|
22
|
-
it "should set body" do
|
23
|
-
@parser.body.should == @ofx.body
|
24
|
-
end
|
25
|
-
|
26
|
-
it "should set account" do
|
27
|
-
@parser.account.should be_a_kind_of(OFX::Account)
|
28
|
-
end
|
29
|
-
|
30
|
-
it "should set account" do
|
31
|
-
@parser.sign_on.should be_a_kind_of(OFX::SignOn)
|
32
|
-
end
|
33
|
-
|
34
|
-
it "should set statements" do
|
35
|
-
@parser.statements.size.should == 1
|
36
|
-
@parser.statements.first.should be_a_kind_of(OFX::Statement)
|
37
|
-
end
|
38
|
-
|
39
|
-
it "should know about all transaction types" do
|
40
|
-
valid_types = [
|
41
|
-
'CREDIT', 'DEBIT', 'INT', 'DIV', 'FEE', 'SRVCHG', 'DEP', 'ATM', 'POS', 'XFER',
|
42
|
-
'CHECK', 'PAYMENT', 'CASH', 'DIRECTDEP', 'DIRECTDEBIT', 'REPEATPMT', 'OTHER'
|
43
|
-
]
|
44
|
-
valid_types.sort.should == OFX::Parser::OFX103::TRANSACTION_TYPES.keys.sort
|
45
|
-
|
46
|
-
valid_types.each do |transaction_type|
|
47
|
-
transaction_type.downcase.to_sym.should equal OFX::Parser::OFX103::TRANSACTION_TYPES[transaction_type]
|
48
|
-
end
|
49
|
-
end
|
50
|
-
end
|