ofx 0.3.2 → 0.3.4
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 +5 -5
- data/README.rdoc +5 -0
- data/lib/ofx/parser/ofx102.rb +133 -66
- data/lib/ofx/parser/ofx103.rb +7 -0
- data/lib/ofx/parser.rb +5 -3
- data/lib/ofx/sign_on.rb +1 -0
- data/lib/ofx/statement.rb +11 -0
- data/lib/ofx/status.rb +12 -0
- data/lib/ofx/transaction.rb +1 -0
- data/lib/ofx/version.rb +1 -1
- data/lib/ofx.rb +19 -14
- data/spec/ofx/account_spec.rb +67 -17
- data/spec/ofx/ofx102_spec.rb +27 -6
- data/spec/ofx/ofx103_spec.rb +50 -0
- data/spec/ofx/ofx211_spec.rb +25 -20
- data/spec/ofx/ofx_parser_spec.rb +24 -3
- data/spec/ofx/sign_on_spec.rb +4 -0
- data/spec/ofx/statement_spec.rb +131 -0
- data/spec/ofx/status_spec.rb +47 -0
- data/spec/ofx/transaction_spec.rb +54 -7
- metadata +36 -71
- data/.gitignore +0 -4
- data/.rspec +0 -1
- data/Gemfile +0 -2
- data/Gemfile.lock +0 -49
- data/ofx.gemspec +0 -34
- data/spec/fixtures/avatar.gif +0 -0
- data/spec/fixtures/bb.ofx +0 -700
- data/spec/fixtures/creditcard.ofx +0 -79
- data/spec/fixtures/invalid_version.ofx +0 -308
- data/spec/fixtures/sample.ofx +0 -314
- data/spec/fixtures/utf8.ofx +0 -308
- data/spec/fixtures/v211.ofx +0 -85
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: f010daf75c910a87b19c737c27a0970a4a410f5e5b6ba5916f4546e2bb5f9abb
|
4
|
+
data.tar.gz: abf6b0090855e5c063ce2d627e8f2b4907be64a71289cb520d4ae4bf7687371e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f3ccb6719848c32e3047243715a3ec2aabbc80b2f241bfd2ff7dcbda819bf1baeb3086ee751459a28643345d4272bf4b4481dd56ba727f9ebf94ea6a680d4cf0
|
7
|
+
data.tar.gz: 48076b4428d20fa368544099691ebe1bf877b724b49cfce83265545a84b62b07e45759e00ae0febaf254090d53c157a1f9b7b6340f5c9d59237aa1847e590ca5
|
data/README.rdoc
CHANGED
@@ -1,5 +1,8 @@
|
|
1
1
|
= OFX
|
2
2
|
|
3
|
+
{<img src="https://badge.fury.io/rb/ofx.png" alt="Gem Version" />}[http://badge.fury.io/rb/ofx]
|
4
|
+
{<img src="https://travis-ci.org/annacruz/ofx.svg?branch=master" alt="Build Status" />}[https://travis-ci.org/annacruz/ofx]
|
5
|
+
|
3
6
|
A simple OFX (Open Financial Exchange) parser built on top of Nokogiri. Currently supports both OFX 1.0.2 and 2.1.1.
|
4
7
|
|
5
8
|
Works on both ruby 1.9 and 2.0.
|
@@ -14,6 +17,8 @@ Works on both ruby 1.9 and 2.0.
|
|
14
17
|
p account.transactions
|
15
18
|
end
|
16
19
|
|
20
|
+
Invalid files will raise an OFX::UnsupportedFileError.
|
21
|
+
|
17
22
|
== Creator
|
18
23
|
|
19
24
|
* Nando Vieira - http://simplesideias.com.br
|
data/lib/ofx/parser/ofx102.rb
CHANGED
@@ -1,20 +1,31 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module OFX
|
2
4
|
module Parser
|
3
5
|
class OFX102
|
4
|
-
VERSION =
|
6
|
+
VERSION = '1.0.2'
|
5
7
|
|
6
8
|
ACCOUNT_TYPES = {
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
9
|
+
'CHECKING' => :checking,
|
10
|
+
'SAVINGS' => :savings,
|
11
|
+
'CREDITLINE' => :creditline,
|
12
|
+
'MONEYMRKT' => :moneymrkt
|
13
|
+
}.freeze
|
14
|
+
|
15
|
+
TRANSACTION_TYPES = %w[
|
16
|
+
ATM CASH CHECK CREDIT DEBIT DEP DIRECTDEBIT DIRECTDEP DIV
|
17
|
+
FEE INT OTHER PAYMENT POS REPEATPMT SRVCHG XFER
|
18
|
+
].each_with_object({}) do |tran_type, hash|
|
19
|
+
hash[tran_type] = tran_type.downcase.to_sym
|
20
|
+
end
|
21
|
+
|
22
|
+
SEVERITY = {
|
23
|
+
'INFO' => :info,
|
24
|
+
'WARN' => :warn,
|
25
|
+
'ERROR' => :error
|
26
|
+
}.freeza
|
27
|
+
|
28
|
+
attr_reader :headers, :body, :html
|
18
29
|
|
19
30
|
def initialize(options = {})
|
20
31
|
@headers = options[:headers]
|
@@ -22,8 +33,17 @@ module OFX
|
|
22
33
|
@html = Nokogiri::HTML.parse(body)
|
23
34
|
end
|
24
35
|
|
36
|
+
def statements
|
37
|
+
@statements ||= html.search('stmttrnrs, ccstmttrnrs').collect { |node| build_statement(node) }
|
38
|
+
end
|
39
|
+
|
40
|
+
def accounts
|
41
|
+
@accounts ||= html.search('stmttrnrs, ccstmttrnrs').collect { |node| build_account(node) }
|
42
|
+
end
|
43
|
+
|
44
|
+
# DEPRECATED: kept for legacy support
|
25
45
|
def account
|
26
|
-
@account ||= build_account
|
46
|
+
@account ||= build_account(html.search('stmttrnrs, ccstmttrnrs').first)
|
27
47
|
end
|
28
48
|
|
29
49
|
def sign_on
|
@@ -32,106 +52,153 @@ module OFX
|
|
32
52
|
|
33
53
|
def self.parse_headers(header_text)
|
34
54
|
# Change single CR's to LF's to avoid issues with some banks
|
35
|
-
header_text.gsub!(/\r(?!\n)/,
|
55
|
+
header_text.gsub!(/\r(?!\n)/, '\n')
|
36
56
|
|
37
57
|
# Parse headers. When value is NONE, convert it to nil.
|
38
|
-
headers = header_text.to_enum(:each_line).
|
58
|
+
headers = header_text.to_enum(:each_line).each_with_object({}) do |line, memo|
|
39
59
|
_, key, value = *line.match(/^(.*?):(.*?)\s*(\r?\n)*$/)
|
40
60
|
|
41
61
|
unless key.nil?
|
42
|
-
memo[key] = value ==
|
62
|
+
memo[key] = value == 'NONE' ? nil : value
|
43
63
|
end
|
44
|
-
|
45
|
-
memo
|
46
64
|
end
|
47
65
|
|
48
66
|
return headers unless headers.empty?
|
49
67
|
end
|
50
68
|
|
51
69
|
private
|
52
|
-
|
70
|
+
|
71
|
+
def build_statement(node)
|
72
|
+
stmrs_node = node.search('stmtrs, ccstmtrs')
|
73
|
+
account = build_account(node)
|
74
|
+
OFX::Statement.new(
|
75
|
+
currency: stmrs_node.search('curdef').inner_text,
|
76
|
+
start_date: build_date(stmrs_node.search('banktranlist > dtstart').inner_text),
|
77
|
+
end_date: build_date(stmrs_node.search('banktranlist > dtend').inner_text),
|
78
|
+
account: account,
|
79
|
+
transactions: account.transactions,
|
80
|
+
balance: account.balance,
|
81
|
+
available_balance: account.available_balance
|
82
|
+
)
|
83
|
+
end
|
84
|
+
|
85
|
+
def build_account(node)
|
53
86
|
OFX::Account.new({
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
87
|
+
bank_id: node.search('bankacctfrom > bankid').inner_text,
|
88
|
+
id: node.search('bankacctfrom > acctid, ccacctfrom > acctid').inner_text,
|
89
|
+
type: ACCOUNT_TYPES[node.search('bankacctfrom > accttype').inner_text.to_s.upcase],
|
90
|
+
transactions: build_transactions(node),
|
91
|
+
balance: build_balance(node),
|
92
|
+
available_balance: build_available_balance(node),
|
93
|
+
currency: node.search('stmtrs > curdef, ccstmtrs > curdef').inner_text
|
94
|
+
})
|
95
|
+
end
|
96
|
+
|
97
|
+
def build_status(node)
|
98
|
+
OFX::Status.new({
|
99
|
+
code: node.search('code').inner_text.to_i,
|
100
|
+
severity: SEVERITY[node.search('severity').inner_text],
|
101
|
+
message: node.search('message').inner_text
|
102
|
+
})
|
63
103
|
end
|
64
104
|
|
65
105
|
def build_sign_on
|
66
106
|
OFX::SignOn.new({
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
107
|
+
language: html.search('signonmsgsrsv1 > sonrs > language').inner_text,
|
108
|
+
fi_id: html.search('signonmsgsrsv1 > sonrs > fi > fid').inner_text,
|
109
|
+
fi_name: html.search('signonmsgsrsv1 > sonrs > fi > org').inner_text,
|
110
|
+
status: build_status(html.search('signonmsgsrsv1 > sonrs > status'))
|
111
|
+
})
|
71
112
|
end
|
72
113
|
|
73
|
-
def build_transactions
|
74
|
-
|
114
|
+
def build_transactions(node)
|
115
|
+
node.search('banktranlist > stmttrn').collect do |element|
|
75
116
|
build_transaction(element)
|
76
117
|
end
|
77
118
|
end
|
78
119
|
|
79
120
|
def build_transaction(element)
|
121
|
+
occurred_at = begin
|
122
|
+
build_date(element.search('dtuser').inner_text)
|
123
|
+
rescue StandardError
|
124
|
+
nil
|
125
|
+
end
|
126
|
+
|
80
127
|
OFX::Transaction.new({
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
128
|
+
amount: build_amount(element),
|
129
|
+
amount_in_pennies: (build_amount(element) * 100).to_i,
|
130
|
+
fit_id: element.search('fitid').inner_text,
|
131
|
+
memo: element.search('memo').inner_text,
|
132
|
+
name: element.search('name').inner_text,
|
133
|
+
payee: element.search('payee').inner_text,
|
134
|
+
check_number: element.search('checknum').inner_text,
|
135
|
+
ref_number: element.search('refnum').inner_text,
|
136
|
+
posted_at: build_date(element.search('dtposted').inner_text),
|
137
|
+
occurred_at:,
|
138
|
+
type: build_type(element),
|
139
|
+
sic: element.search('sic').inner_text
|
140
|
+
})
|
93
141
|
end
|
94
142
|
|
95
143
|
def build_type(element)
|
96
|
-
TRANSACTION_TYPES[element.search(
|
144
|
+
TRANSACTION_TYPES[element.search('trntype').inner_text.to_s.upcase]
|
97
145
|
end
|
98
146
|
|
99
147
|
def build_amount(element)
|
100
|
-
|
148
|
+
to_decimal(element.search('trnamt').inner_text)
|
101
149
|
end
|
102
150
|
|
151
|
+
# Input format is `YYYYMMDDHHMMSS.XXX[gmt offset[:tz name]]`
|
103
152
|
def build_date(date)
|
104
|
-
|
153
|
+
tz_pattern = /(?:\[([+-]?\d{1,4}):\S{3}\])?\z/
|
154
|
+
|
155
|
+
# Timezone offset handling
|
156
|
+
date.sub!(tz_pattern, '')
|
157
|
+
offset = Regexp.last_match(1)
|
158
|
+
|
159
|
+
if offset
|
160
|
+
# Offset padding
|
161
|
+
_, hours, mins = *offset.match(/\A([+-]?\d{1,2})(\d{0,2})?\z/)
|
162
|
+
offset = format('%+03d%02d', hours.to_i, mins.to_i)
|
163
|
+
else
|
164
|
+
offset = '+0000'
|
165
|
+
end
|
105
166
|
|
106
|
-
date
|
107
|
-
date << "#{hour}:#{minutes}:#{seconds}" if hour && minutes && seconds
|
167
|
+
date << ' #{offset}'
|
108
168
|
|
109
169
|
Time.parse(date)
|
110
170
|
end
|
111
171
|
|
112
|
-
def build_balance
|
113
|
-
amount =
|
172
|
+
def build_balance(node)
|
173
|
+
amount = to_decimal(node.search('ledgerbal > balamt').inner_text)
|
174
|
+
posted_at = begin
|
175
|
+
build_date(node.search('ledgerbal > dtasof').inner_text)
|
176
|
+
rescue StandardError
|
177
|
+
nil
|
178
|
+
end
|
114
179
|
|
115
180
|
OFX::Balance.new({
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
181
|
+
amount:,
|
182
|
+
amount_in_pennies: (amount * 100).to_i,
|
183
|
+
posted_at:
|
184
|
+
})
|
120
185
|
end
|
121
186
|
|
122
|
-
def build_available_balance
|
123
|
-
if
|
124
|
-
amount =
|
187
|
+
def build_available_balance(node)
|
188
|
+
if node.search('availbal').size > 0
|
189
|
+
amount = to_decimal(node.search('availbal > balamt').inner_text)
|
125
190
|
|
126
191
|
OFX::Balance.new({
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
else
|
132
|
-
return nil
|
192
|
+
amount:,
|
193
|
+
amount_in_pennies: (amount * 100).to_i,
|
194
|
+
posted_at: build_date(node.search('availbal > dtasof').inner_text)
|
195
|
+
})
|
133
196
|
end
|
134
197
|
end
|
198
|
+
|
199
|
+
def to_decimal(amount)
|
200
|
+
BigDecimal(amount.to_s.gsub(',', '.'))
|
201
|
+
end
|
135
202
|
end
|
136
203
|
end
|
137
204
|
end
|
data/lib/ofx/parser.rb
CHANGED
@@ -12,14 +12,16 @@ module OFX
|
|
12
12
|
begin
|
13
13
|
@content = convert_to_utf8(resource.read)
|
14
14
|
@headers, @body = prepare(content)
|
15
|
-
rescue
|
15
|
+
rescue
|
16
16
|
raise OFX::UnsupportedFileError
|
17
17
|
end
|
18
18
|
|
19
19
|
case headers["VERSION"]
|
20
20
|
when /102/ then
|
21
21
|
@parser = OFX102.new(:headers => headers, :body => body)
|
22
|
-
when /
|
22
|
+
when /103/ then
|
23
|
+
@parser = OFX103.new(:headers => headers, :body => body)
|
24
|
+
when /200|202|211|220/ then
|
23
25
|
@parser = OFX211.new(:headers => headers, :body => body)
|
24
26
|
else
|
25
27
|
raise OFX::UnsupportedFileError
|
@@ -32,7 +34,7 @@ module OFX
|
|
32
34
|
else
|
33
35
|
open(resource)
|
34
36
|
end
|
35
|
-
rescue
|
37
|
+
rescue
|
36
38
|
StringIO.new(resource)
|
37
39
|
end
|
38
40
|
|
data/lib/ofx/sign_on.rb
CHANGED
data/lib/ofx/status.rb
ADDED
data/lib/ofx/transaction.rb
CHANGED
data/lib/ofx/version.rb
CHANGED
data/lib/ofx.rb
CHANGED
@@ -1,19 +1,24 @@
|
|
1
|
-
|
2
|
-
require "nokogiri"
|
3
|
-
require "bigdecimal"
|
1
|
+
# frozen_string_literal: true
|
4
2
|
|
5
|
-
require
|
3
|
+
require 'open-uri'
|
4
|
+
require 'nokogiri'
|
5
|
+
require 'bigdecimal'
|
6
6
|
|
7
|
-
require
|
8
|
-
|
9
|
-
require
|
10
|
-
require
|
11
|
-
require
|
12
|
-
require
|
13
|
-
require
|
14
|
-
require
|
15
|
-
require
|
16
|
-
require
|
7
|
+
require 'kconv'
|
8
|
+
|
9
|
+
require 'ofx/errors'
|
10
|
+
require 'ofx/parser'
|
11
|
+
require 'ofx/parser/ofx102'
|
12
|
+
require 'ofx/parser/ofx103'
|
13
|
+
require 'ofx/parser/ofx211'
|
14
|
+
require 'ofx/foundation'
|
15
|
+
require 'ofx/balance'
|
16
|
+
require 'ofx/account'
|
17
|
+
require 'ofx/sign_on'
|
18
|
+
require 'ofx/status'
|
19
|
+
require 'ofx/statement'
|
20
|
+
require 'ofx/transaction'
|
21
|
+
require 'ofx/version'
|
17
22
|
|
18
23
|
def OFX(resource, &block)
|
19
24
|
parser = OFX::Parser::Base.new(resource).parser
|
data/spec/ofx/account_spec.rb
CHANGED
@@ -11,49 +11,49 @@ describe OFX::Account do
|
|
11
11
|
it "should return currency" do
|
12
12
|
@account.currency.should == "BRL"
|
13
13
|
end
|
14
|
-
|
14
|
+
|
15
15
|
it "should return bank id" do
|
16
16
|
@account.bank_id.should == "0356"
|
17
17
|
end
|
18
|
-
|
18
|
+
|
19
19
|
it "should return id" do
|
20
20
|
@account.id.should == "03227113109"
|
21
21
|
end
|
22
|
-
|
22
|
+
|
23
23
|
it "should return type" do
|
24
24
|
@account.type.should == :checking
|
25
25
|
end
|
26
|
-
|
26
|
+
|
27
27
|
it "should return transactions" do
|
28
28
|
@account.transactions.should be_a_kind_of(Array)
|
29
29
|
@account.transactions.size.should == 36
|
30
30
|
end
|
31
|
-
|
31
|
+
|
32
32
|
it "should return balance" do
|
33
|
-
@account.balance.amount.should == 598.44
|
33
|
+
@account.balance.amount.should == BigDecimal('598.44')
|
34
34
|
end
|
35
|
-
|
35
|
+
|
36
36
|
it "should return balance in pennies" do
|
37
37
|
@account.balance.amount_in_pennies.should == 59844
|
38
38
|
end
|
39
|
-
|
39
|
+
|
40
40
|
it "should return balance date" do
|
41
|
-
@account.balance.posted_at.should == Time.
|
41
|
+
@account.balance.posted_at.should == Time.gm(2009,11,1)
|
42
42
|
end
|
43
|
-
|
43
|
+
|
44
44
|
context "available_balance" do
|
45
45
|
it "should return available balance" do
|
46
|
-
@account.available_balance.amount.should == 1555.99
|
46
|
+
@account.available_balance.amount.should == BigDecimal('1555.99')
|
47
47
|
end
|
48
|
-
|
48
|
+
|
49
49
|
it "should return available balance in pennies" do
|
50
50
|
@account.available_balance.amount_in_pennies.should == 155599
|
51
51
|
end
|
52
|
-
|
52
|
+
|
53
53
|
it "should return available balance date" do
|
54
|
-
@account.available_balance.posted_at.should == Time.
|
54
|
+
@account.available_balance.posted_at.should == Time.gm(2009,11,1)
|
55
55
|
end
|
56
|
-
|
56
|
+
|
57
57
|
it "should return nil if AVAILBAL not found" do
|
58
58
|
@ofx = OFX::Parser::Base.new("spec/fixtures/utf8.ofx")
|
59
59
|
@parser = @ofx.parser
|
@@ -61,7 +61,7 @@ describe OFX::Account do
|
|
61
61
|
@account.available_balance.should be_nil
|
62
62
|
end
|
63
63
|
end
|
64
|
-
|
64
|
+
|
65
65
|
context "Credit Card" do
|
66
66
|
before do
|
67
67
|
@ofx = OFX::Parser::Base.new("spec/fixtures/creditcard.ofx")
|
@@ -72,10 +72,60 @@ describe OFX::Account do
|
|
72
72
|
it "should return id" do
|
73
73
|
@account.id.should == "XXXXXXXXXXXX1111"
|
74
74
|
end
|
75
|
-
|
75
|
+
|
76
76
|
it "should return currency" do
|
77
77
|
@account.currency.should == "USD"
|
78
78
|
end
|
79
79
|
end
|
80
|
+
context "With Issue" do # Bradesco do not provide a valid date in balance
|
81
|
+
before do
|
82
|
+
@ofx = OFX::Parser::Base.new("spec/fixtures/dtsof_balance_issue.ofx")
|
83
|
+
@parser = @ofx.parser
|
84
|
+
@account = @parser.account
|
85
|
+
end
|
86
|
+
|
87
|
+
it "should return nil for date balance" do
|
88
|
+
@account.balance.posted_at.should be_nil
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
context "Invalid Dates" do
|
93
|
+
before do
|
94
|
+
@ofx = OFX::Parser::Base.new("spec/fixtures/bradesco.ofx")
|
95
|
+
@parser = @ofx.parser
|
96
|
+
end
|
97
|
+
it "should not raise error when balance has date zero" do
|
98
|
+
expect { @parser.account.balance }.to_not raise_error
|
99
|
+
end
|
100
|
+
it "should return NIL in balance.posted_at when balance date is zero" do
|
101
|
+
@parser.account.balance.posted_at.should be_nil
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
context "decimal values using a comma" do
|
106
|
+
before do
|
107
|
+
@ofx = OFX::Parser::Base.new("spec/fixtures/santander.ofx")
|
108
|
+
@parser = @ofx.parser
|
109
|
+
@account = @parser.account
|
110
|
+
end
|
111
|
+
|
112
|
+
it "should return balance" do
|
113
|
+
@account.balance.amount.should == BigDecimal('348.29')
|
114
|
+
end
|
115
|
+
|
116
|
+
it "should return balance in pennies" do
|
117
|
+
@account.balance.amount_in_pennies.should == 34829
|
118
|
+
end
|
119
|
+
|
120
|
+
context "available_balance" do
|
121
|
+
it "should return available balance" do
|
122
|
+
@account.available_balance.amount.should == BigDecimal('2415.87')
|
123
|
+
end
|
124
|
+
|
125
|
+
it "should return available balance in pennies" do
|
126
|
+
@account.available_balance.amount_in_pennies.should == 241587
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
80
130
|
end
|
81
131
|
end
|
data/spec/ofx/ofx102_spec.rb
CHANGED
@@ -5,11 +5,11 @@ describe OFX::Parser::OFX102 do
|
|
5
5
|
@ofx = OFX::Parser::Base.new("spec/fixtures/sample.ofx")
|
6
6
|
@parser = @ofx.parser
|
7
7
|
end
|
8
|
-
|
8
|
+
|
9
9
|
it "should have a version" do
|
10
10
|
OFX::Parser::OFX102::VERSION.should == "1.0.2"
|
11
11
|
end
|
12
|
-
|
12
|
+
|
13
13
|
it "should set headers" do
|
14
14
|
@parser.headers.should == @ofx.headers
|
15
15
|
end
|
@@ -22,7 +22,7 @@ describe OFX::Parser::OFX102 do
|
|
22
22
|
it "should set body" do
|
23
23
|
@parser.body.should == @ofx.body
|
24
24
|
end
|
25
|
-
|
25
|
+
|
26
26
|
it "should set account" do
|
27
27
|
@parser.account.should be_a_kind_of(OFX::Account)
|
28
28
|
end
|
@@ -30,17 +30,38 @@ describe OFX::Parser::OFX102 do
|
|
30
30
|
it "should set account" do
|
31
31
|
@parser.sign_on.should be_a_kind_of(OFX::SignOn)
|
32
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
|
33
38
|
|
34
39
|
it "should know about all transaction types" do
|
35
40
|
valid_types = [
|
36
|
-
'CREDIT', 'DEBIT', 'INT', 'DIV', 'FEE', 'SRVCHG', 'DEP', 'ATM', 'POS', 'XFER',
|
41
|
+
'CREDIT', 'DEBIT', 'INT', 'DIV', 'FEE', 'SRVCHG', 'DEP', 'ATM', 'POS', 'XFER',
|
37
42
|
'CHECK', 'PAYMENT', 'CASH', 'DIRECTDEP', 'DIRECTDEBIT', 'REPEATPMT', 'OTHER'
|
38
43
|
]
|
39
44
|
valid_types.sort.should == OFX::Parser::OFX102::TRANSACTION_TYPES.keys.sort
|
40
|
-
|
45
|
+
|
41
46
|
valid_types.each do |transaction_type|
|
42
47
|
transaction_type.downcase.to_sym.should equal OFX::Parser::OFX102::TRANSACTION_TYPES[transaction_type]
|
43
48
|
end
|
44
49
|
end
|
45
|
-
|
50
|
+
|
51
|
+
describe "#build_date" do
|
52
|
+
context "without a Time Zone" do
|
53
|
+
it "should default to GMT" do
|
54
|
+
@parser.send(:build_date, "20170904").should == Time.gm(2017, 9, 4)
|
55
|
+
@parser.send(:build_date, "20170904082855").should == Time.gm(2017, 9, 4, 8, 28, 55)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
context "with a Time Zone" do
|
60
|
+
it "should returns the correct date" do
|
61
|
+
@parser.send(:build_date, "20150507164333[-0300:BRT]").should == Time.new(2015, 5, 7, 16, 43, 33, "-03:00")
|
62
|
+
@parser.send(:build_date, "20180507120000[0:GMT]").should == Time.gm(2018, 5, 7, 12)
|
63
|
+
@parser.send(:build_date, "20170904082855[-3:GMT]").should == Time.new(2017, 9, 4, 8, 28, 55, "-03:00")
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
46
67
|
end
|