ofx_br 0.3.3
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 +7 -0
- data/.github/dependabot.yml +13 -0
- data/.gitignore +4 -0
- data/.rspec +1 -0
- data/.travis.yml +9 -0
- data/Gemfile +2 -0
- data/Gemfile.lock +50 -0
- data/README.rdoc +51 -0
- data/Rakefile +7 -0
- data/lib/ofx_br/account.rb +11 -0
- data/lib/ofx_br/balance.rb +7 -0
- data/lib/ofx_br/errors.rb +3 -0
- data/lib/ofx_br/foundation.rb +9 -0
- data/lib/ofx_br/parser/ofx102.rb +201 -0
- data/lib/ofx_br/parser/ofx103.rb +7 -0
- data/lib/ofx_br/parser/ofx211.rb +40 -0
- data/lib/ofx_br/parser.rb +72 -0
- data/lib/ofx_br/sign_on.rb +8 -0
- data/lib/ofx_br/statement.rb +5 -0
- data/lib/ofx_br/status.rb +12 -0
- data/lib/ofx_br/transaction.rb +16 -0
- data/lib/ofx_br/version.rb +8 -0
- data/lib/ofx_br.rb +33 -0
- data/ofx_br.gemspec +32 -0
- data/spec/fixtures/avatar.gif +0 -0
- data/spec/fixtures/bb.ofx +700 -0
- data/spec/fixtures/bradesco.ofx +96 -0
- data/spec/fixtures/creditcard.ofx +79 -0
- data/spec/fixtures/dtsof_balance_issue.ofx +54 -0
- data/spec/fixtures/error.ofx +24 -0
- data/spec/fixtures/invalid_version.ofx +308 -0
- data/spec/fixtures/nd-amex-sample.ofx +12 -0
- data/spec/fixtures/sample.ofx +315 -0
- data/spec/fixtures/santander.ofx +91 -0
- data/spec/fixtures/utf8.ofx +308 -0
- data/spec/fixtures/v103.ofx +80 -0
- data/spec/fixtures/v211.ofx +85 -0
- data/spec/ofx_br/account_spec.rb +131 -0
- data/spec/ofx_br/ofx102_spec.rb +67 -0
- data/spec/ofx_br/ofx103_spec.rb +50 -0
- data/spec/ofx_br/ofx211_spec.rb +84 -0
- data/spec/ofx_br/ofx_parser_spec.rb +123 -0
- data/spec/ofx_br/ofx_spec.rb +21 -0
- data/spec/ofx_br/sign_on_spec.rb +27 -0
- data/spec/ofx_br/statement_spec.rb +131 -0
- data/spec/ofx_br/status_spec.rb +47 -0
- data/spec/ofx_br/transaction_spec.rb +201 -0
- data/spec/spec_helper.rb +9 -0
- metadata +174 -0
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
|
|
2
|
+
|
|
3
|
+
OFXHEADER:100
|
|
4
|
+
DATA:OFXSGML
|
|
5
|
+
VERSION:103
|
|
6
|
+
SECURITY:NONE
|
|
7
|
+
ENCODING:USASCII
|
|
8
|
+
CHARSET:1252
|
|
9
|
+
COMPRESSION:NONE
|
|
10
|
+
OLDFILEUID:NONE
|
|
11
|
+
NEWFILEUID:NONE
|
|
12
|
+
|
|
13
|
+
<OFX>
|
|
14
|
+
<SIGNONMSGSRSV1>
|
|
15
|
+
<SONRS>
|
|
16
|
+
<STATUS>
|
|
17
|
+
<CODE>0</CODE>
|
|
18
|
+
<SEVERITY>INFO</SEVERITY>
|
|
19
|
+
</STATUS>
|
|
20
|
+
<DTSERVER>20150507164333.979[-0300:BRT]</DTSERVER>
|
|
21
|
+
<LANGUAGE>POR</LANGUAGE>
|
|
22
|
+
<FI>
|
|
23
|
+
<ORG>HSBC Bank Brasil S.A.</ORG>
|
|
24
|
+
<FID>1</FID>
|
|
25
|
+
</FI>
|
|
26
|
+
</SONRS>
|
|
27
|
+
</SIGNONMSGSRSV1>
|
|
28
|
+
<BANKMSGSRSV1>
|
|
29
|
+
<STMTTRNRS>
|
|
30
|
+
<TRNUID>1</TRNUID>
|
|
31
|
+
<STATUS>
|
|
32
|
+
<CODE>0</CODE>
|
|
33
|
+
<SEVERITY>INFO</SEVERITY>
|
|
34
|
+
</STATUS>
|
|
35
|
+
<STMTRS>
|
|
36
|
+
<CURDEF>BRL</CURDEF>
|
|
37
|
+
<BANKACCTFROM>
|
|
38
|
+
<BANKID>399</BANKID>
|
|
39
|
+
<ACCTID>26215973324</ACCTID>
|
|
40
|
+
<ACCTTYPE>CHECKING</ACCTTYPE>
|
|
41
|
+
</BANKACCTFROM>
|
|
42
|
+
<BANKTRANLIST>
|
|
43
|
+
<DTSTART>20150501</DTSTART>
|
|
44
|
+
<DTEND>20150507</DTEND>
|
|
45
|
+
|
|
46
|
+
<STMTTRN>
|
|
47
|
+
<TRNTYPE>PAYMENT</TRNTYPE>
|
|
48
|
+
<DTPOSTED>20150504120000</DTPOSTED>
|
|
49
|
+
<DTUSER>20150504120000</DTUSER>
|
|
50
|
+
<TRNAMT>-1020.88</TRNAMT>
|
|
51
|
+
<FITID>201505041</FITID>
|
|
52
|
+
<CHECKNUM>0390003</CHECKNUM>
|
|
53
|
+
<NAME>PAGAMENTO TITULO-CNB </NAME>
|
|
54
|
+
<MEMO>PAGAMENTO TITULO-CNB </MEMO>
|
|
55
|
+
</STMTTRN>
|
|
56
|
+
|
|
57
|
+
<STMTTRN>
|
|
58
|
+
<TRNTYPE>PAYMENT</TRNTYPE>
|
|
59
|
+
<DTPOSTED>20150505120000</DTPOSTED>
|
|
60
|
+
<DTUSER>20150505120000</DTUSER>
|
|
61
|
+
<TRNAMT>-82.10</TRNAMT>
|
|
62
|
+
<FITID>201505051</FITID>
|
|
63
|
+
<CHECKNUM>0000000</CHECKNUM>
|
|
64
|
+
<NAME>TAR PACOTE MENSAL </NAME>
|
|
65
|
+
<MEMO>TAR PACOTE MENSAL </MEMO>
|
|
66
|
+
</STMTTRN>
|
|
67
|
+
|
|
68
|
+
</BANKTRANLIST>
|
|
69
|
+
<LEDGERBAL>
|
|
70
|
+
<BALAMT>3806.63</BALAMT>
|
|
71
|
+
<DTASOF>20150507164333.980[-0300:BRT]</DTASOF>
|
|
72
|
+
</LEDGERBAL>
|
|
73
|
+
<AVAILBAL>
|
|
74
|
+
<BALAMT>3806.63</BALAMT>
|
|
75
|
+
<DTASOF>20150507164333.980[-0300:BRT]</DTASOF>
|
|
76
|
+
</AVAILBAL>
|
|
77
|
+
</STMTRS>
|
|
78
|
+
</STMTTRNRS>
|
|
79
|
+
</BANKMSGSRSV1>
|
|
80
|
+
</OFX>
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="US-ASCII"?>
|
|
2
|
+
|
|
3
|
+
<!-- This example is taken from the 2.1.1 specification, pages 610-612 -->
|
|
4
|
+
<?OFX OFXHEADER="200" VERSION="211" SECURITY="NONE" OLDFILEUID="NONE" NEWFILEUID="NONE"?>
|
|
5
|
+
<OFX>
|
|
6
|
+
<SIGNONMSGSRSV1>
|
|
7
|
+
<SONRS>
|
|
8
|
+
<STATUS>
|
|
9
|
+
<CODE>0</CODE>
|
|
10
|
+
<SEVERITY>INFO</SEVERITY>
|
|
11
|
+
</STATUS>
|
|
12
|
+
<DTSERVER>20050831165153.000[-8:PST]</DTSERVER>
|
|
13
|
+
<LANGUAGE>ENG</LANGUAGE>
|
|
14
|
+
</SONRS>
|
|
15
|
+
</SIGNONMSGSRSV1>
|
|
16
|
+
<BANKMSGSRSV1>
|
|
17
|
+
<STMTTRNRS>
|
|
18
|
+
<TRNUID>0</TRNUID>
|
|
19
|
+
<STATUS>
|
|
20
|
+
<CODE>0</CODE>
|
|
21
|
+
<SEVERITY>INFO</SEVERITY>
|
|
22
|
+
</STATUS>
|
|
23
|
+
<STMTRS>
|
|
24
|
+
<CURDEF>USD</CURDEF>
|
|
25
|
+
<BANKACCTFROM>
|
|
26
|
+
<BANKID>000000123</BANKID>
|
|
27
|
+
<ACCTID>123456</ACCTID>
|
|
28
|
+
<ACCTTYPE>CHECKING</ACCTTYPE>
|
|
29
|
+
</BANKACCTFROM>
|
|
30
|
+
<BANKTRANLIST>
|
|
31
|
+
<DTSTART>20040801</DTSTART>
|
|
32
|
+
<DTEND>20050831165153.000[-8:PST]</DTEND>
|
|
33
|
+
<STMTTRN>
|
|
34
|
+
<TRNTYPE>POS</TRNTYPE>
|
|
35
|
+
<DTPOSTED>20050824080000</DTPOSTED>
|
|
36
|
+
<TRNAMT>-80</TRNAMT>
|
|
37
|
+
<FITID>219378</FITID>
|
|
38
|
+
<NAME>FrogKick Scuba Gear</NAME>
|
|
39
|
+
</STMTTRN>
|
|
40
|
+
</BANKTRANLIST>
|
|
41
|
+
<LEDGERBAL>
|
|
42
|
+
<BALAMT>2156.56</BALAMT>
|
|
43
|
+
<DTASOF>20050831165153</DTASOF>
|
|
44
|
+
</LEDGERBAL>
|
|
45
|
+
</STMTRS>
|
|
46
|
+
</STMTTRNRS>
|
|
47
|
+
</BANKMSGSRSV1>
|
|
48
|
+
<CREDITCARDMSGSRSV1>
|
|
49
|
+
<CCSTMTTRNRS>
|
|
50
|
+
<TRNUID>0</TRNUID>
|
|
51
|
+
<STATUS>
|
|
52
|
+
<CODE>0</CODE>
|
|
53
|
+
<SEVERITY>INFO</SEVERITY>
|
|
54
|
+
</STATUS>
|
|
55
|
+
<CCSTMTRS>
|
|
56
|
+
<CURDEF>USD</CURDEF>
|
|
57
|
+
<CCACCTFROM>
|
|
58
|
+
<ACCTID>123412341234</ACCTID>
|
|
59
|
+
</CCACCTFROM>
|
|
60
|
+
<BANKTRANLIST>
|
|
61
|
+
<DTSTART>20050801</DTSTART>
|
|
62
|
+
<DTEND>20050831165153.000[-8:PST]</DTEND>
|
|
63
|
+
<STMTTRN>
|
|
64
|
+
<TRNTYPE>INT</TRNTYPE>
|
|
65
|
+
<DTPOSTED>20050811080000</DTPOSTED>
|
|
66
|
+
<TRNAMT>-23.00</TRNAMT>
|
|
67
|
+
<FITID>219867</FITID>
|
|
68
|
+
<NAME>Interest Charge</NAME>
|
|
69
|
+
</STMTTRN>
|
|
70
|
+
<STMTTRN>
|
|
71
|
+
<TRNTYPE>CREDIT</TRNTYPE>
|
|
72
|
+
<DTPOSTED>20050811080000</DTPOSTED>
|
|
73
|
+
<TRNAMT>350.00</TRNAMT>
|
|
74
|
+
<FITID>219868</FITID>
|
|
75
|
+
<NAME>Payment - Thank You</NAME>
|
|
76
|
+
</STMTTRN>
|
|
77
|
+
</BANKTRANLIST>
|
|
78
|
+
<LEDGERBAL>
|
|
79
|
+
<BALAMT>-562.00</BALAMT>
|
|
80
|
+
<DTASOF>20050831165153</DTASOF>
|
|
81
|
+
</LEDGERBAL>
|
|
82
|
+
</CCSTMTRS>
|
|
83
|
+
</CCSTMTTRNRS>
|
|
84
|
+
</CREDITCARDMSGSRSV1>
|
|
85
|
+
</OFX>
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
require "spec_helper"
|
|
2
|
+
|
|
3
|
+
describe OFX::Account do
|
|
4
|
+
before do
|
|
5
|
+
@ofx = OFX::Parser::Base.new("spec/fixtures/sample.ofx")
|
|
6
|
+
@parser = @ofx.parser
|
|
7
|
+
@account = @parser.account
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
describe "account" do
|
|
11
|
+
it "should return currency" do
|
|
12
|
+
@account.currency.should == "BRL"
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
it "should return bank id" do
|
|
16
|
+
@account.bank_id.should == "0356"
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
it "should return id" do
|
|
20
|
+
@account.id.should == "03227113109"
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
it "should return type" do
|
|
24
|
+
@account.type.should == :checking
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
it "should return transactions" do
|
|
28
|
+
@account.transactions.should be_a_kind_of(Array)
|
|
29
|
+
@account.transactions.size.should == 36
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
it "should return balance" do
|
|
33
|
+
@account.balance.amount.should == BigDecimal('598.44')
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
it "should return balance in pennies" do
|
|
37
|
+
@account.balance.amount_in_pennies.should == 59844
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
it "should return balance date" do
|
|
41
|
+
@account.balance.posted_at.should == Time.gm(2009,11,1)
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
context "available_balance" do
|
|
45
|
+
it "should return available balance" do
|
|
46
|
+
@account.available_balance.amount.should == BigDecimal('1555.99')
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
it "should return available balance in pennies" do
|
|
50
|
+
@account.available_balance.amount_in_pennies.should == 155599
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
it "should return available balance date" do
|
|
54
|
+
@account.available_balance.posted_at.should == Time.gm(2009,11,1)
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
it "should return nil if AVAILBAL not found" do
|
|
58
|
+
@ofx = OFX::Parser::Base.new("spec/fixtures/utf8.ofx")
|
|
59
|
+
@parser = @ofx.parser
|
|
60
|
+
@account = @parser.account
|
|
61
|
+
@account.available_balance.should be_nil
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
context "Credit Card" do
|
|
66
|
+
before do
|
|
67
|
+
@ofx = OFX::Parser::Base.new("spec/fixtures/creditcard.ofx")
|
|
68
|
+
@parser = @ofx.parser
|
|
69
|
+
@account = @parser.account
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
it "should return id" do
|
|
73
|
+
@account.id.should == "XXXXXXXXXXXX1111"
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
it "should return currency" do
|
|
77
|
+
@account.currency.should == "USD"
|
|
78
|
+
end
|
|
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
|
|
130
|
+
end
|
|
131
|
+
end
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
require "spec_helper"
|
|
2
|
+
|
|
3
|
+
describe OFX::Parser::OFX102 do
|
|
4
|
+
before do
|
|
5
|
+
@ofx = OFX::Parser::Base.new("spec/fixtures/sample.ofx")
|
|
6
|
+
@parser = @ofx.parser
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
it "should have a version" do
|
|
10
|
+
OFX::Parser::OFX102::VERSION.should == "1.0.2"
|
|
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::OFX102.parse_headers("VERSION:102 ")
|
|
19
|
+
headers["VERSION"].should == "102"
|
|
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::OFX102::TRANSACTION_TYPES.keys.sort
|
|
45
|
+
|
|
46
|
+
valid_types.each do |transaction_type|
|
|
47
|
+
transaction_type.downcase.to_sym.should equal OFX::Parser::OFX102::TRANSACTION_TYPES[transaction_type]
|
|
48
|
+
end
|
|
49
|
+
end
|
|
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
|
|
67
|
+
end
|
|
@@ -0,0 +1,50 @@
|
|
|
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
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
require "spec_helper"
|
|
2
|
+
|
|
3
|
+
describe OFX::Parser::OFX211 do
|
|
4
|
+
before do
|
|
5
|
+
@ofx = OFX::Parser::Base.new("spec/fixtures/v211.ofx")
|
|
6
|
+
@parser = @ofx.parser
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
it "should have a version" do
|
|
10
|
+
OFX::Parser::OFX211::VERSION.should == "2.1.1"
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
it "should set headers" do
|
|
14
|
+
@parser.headers.should == @ofx.headers
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
it "should set body" do
|
|
18
|
+
@parser.body.should == @ofx.body
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
it "should set account" do
|
|
22
|
+
@parser.account.should be_a_kind_of(OFX::Account)
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
it "should set account" do
|
|
26
|
+
@parser.sign_on.should be_a_kind_of(OFX::SignOn)
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
it "should set accounts" do
|
|
30
|
+
@parser.accounts.size.should == 2
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
it "should set statements" do
|
|
34
|
+
@parser.statements.size.should == 2
|
|
35
|
+
@parser.statements.first.should be_a_kind_of(OFX::Statement)
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
context "transactions" do
|
|
39
|
+
# Test file contains only three transactions. Let's just check
|
|
40
|
+
# them all.
|
|
41
|
+
context "first" do
|
|
42
|
+
before do
|
|
43
|
+
@t = @parser.accounts[0].transactions[0]
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
it "should contain the correct values" do
|
|
47
|
+
@t.amount.should == BigDecimal('-80')
|
|
48
|
+
@t.fit_id.should == "219378"
|
|
49
|
+
@t.memo.should be_empty
|
|
50
|
+
@t.posted_at.should == Time.parse("2005-08-24 08:00:00 +0000")
|
|
51
|
+
@t.name.should == "FrogKick Scuba Gear"
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
context "second" do
|
|
56
|
+
before do
|
|
57
|
+
@t = @parser.accounts[1].transactions[0]
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
it "should contain the correct values" do
|
|
61
|
+
@t.amount.should == BigDecimal('-23')
|
|
62
|
+
@t.fit_id.should == "219867"
|
|
63
|
+
@t.memo.should be_empty
|
|
64
|
+
@t.posted_at.should == Time.parse("2005-08-11 08:00:00 +0000")
|
|
65
|
+
@t.name.should == "Interest Charge"
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
context "third" do
|
|
70
|
+
before do
|
|
71
|
+
@t = @parser.accounts[1].transactions[1]
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
it "should contain the correct values" do
|
|
75
|
+
@t.amount.should == BigDecimal('350')
|
|
76
|
+
@t.fit_id.should == "219868"
|
|
77
|
+
@t.memo.should be_empty
|
|
78
|
+
@t.posted_at.should == Time.parse("2005-08-11 08:00:00 +0000")
|
|
79
|
+
@t.name.should == "Payment - Thank You"
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
require "spec_helper"
|
|
2
|
+
|
|
3
|
+
describe OFX::Parser do
|
|
4
|
+
before do
|
|
5
|
+
@ofx = OFX::Parser::Base.new("spec/fixtures/sample.ofx")
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
it "should accept file path" do
|
|
9
|
+
@ofx = OFX::Parser::Base.new("spec/fixtures/sample.ofx")
|
|
10
|
+
@ofx.content.should_not be_nil
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
it "should accept file handler" do
|
|
14
|
+
file = open("spec/fixtures/sample.ofx")
|
|
15
|
+
@ofx = OFX::Parser::Base.new(file)
|
|
16
|
+
@ofx.content.should_not be_nil
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
it "should accept file content" do
|
|
20
|
+
file = open("spec/fixtures/sample.ofx").read
|
|
21
|
+
@ofx = OFX::Parser::Base.new(file)
|
|
22
|
+
@ofx.content.should_not be_nil
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
it "should set content" do
|
|
26
|
+
@ofx.content.should == open("spec/fixtures/sample.ofx").read
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
it "should work with UTF8 and Latin1 encodings" do
|
|
30
|
+
@ofx = OFX::Parser::Base.new("spec/fixtures/utf8.ofx")
|
|
31
|
+
@ofx.content.should == open("spec/fixtures/utf8.ofx").read
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
it "should set body" do
|
|
35
|
+
@ofx.body.should_not be_nil
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
it "should raise exception when trying to parse an unsupported OFX version" do
|
|
39
|
+
lambda {
|
|
40
|
+
OFX::Parser::Base.new("spec/fixtures/invalid_version.ofx")
|
|
41
|
+
}.should raise_error(OFX::UnsupportedFileError)
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
it "should raise exception when trying to parse an invalid file" do
|
|
45
|
+
lambda {
|
|
46
|
+
OFX::Parser::Base.new("spec/fixtures/avatar.gif")
|
|
47
|
+
}.should raise_error(OFX::UnsupportedFileError)
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
it "should use 211 parser to parse version 200 ofx files" do
|
|
51
|
+
OFX::Parser::OFX211.stub(:new).and_return('ofx-211-parser')
|
|
52
|
+
ofx = OFX::Parser::Base.new(ofx_2_example('200'))
|
|
53
|
+
ofx.parser.should == 'ofx-211-parser'
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
it "should use 211 parser to parse version 202 ofx files" do
|
|
57
|
+
OFX::Parser::OFX211.stub(:new).and_return('ofx-211-parser')
|
|
58
|
+
ofx = OFX::Parser::Base.new(ofx_2_example('202'))
|
|
59
|
+
ofx.parser.should == 'ofx-211-parser'
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
describe "headers" do
|
|
63
|
+
it "should have OFXHEADER" do
|
|
64
|
+
@ofx.headers["OFXHEADER"].should == "100"
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
it "should have DATA" do
|
|
68
|
+
@ofx.headers["DATA"].should == "OFXSGML"
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
it "should have VERSION" do
|
|
72
|
+
@ofx.headers["VERSION"].should == "102"
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
it "should have SECURITY" do
|
|
76
|
+
@ofx.headers.should have_key("SECURITY")
|
|
77
|
+
@ofx.headers["SECURITY"].should be_nil
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
it "should have ENCODING" do
|
|
81
|
+
@ofx.headers["ENCODING"].should == "USASCII"
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
it "should have CHARSET" do
|
|
85
|
+
@ofx.headers["CHARSET"].should == "1252"
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
it "should have COMPRESSION" do
|
|
89
|
+
@ofx.headers.should have_key("COMPRESSION")
|
|
90
|
+
@ofx.headers["COMPRESSION"].should be_nil
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
it "should have OLDFILEUID" do
|
|
94
|
+
@ofx.headers.should have_key("OLDFILEUID")
|
|
95
|
+
@ofx.headers["OLDFILEUID"].should be_nil
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
it "should have NEWFILEUID" do
|
|
99
|
+
@ofx.headers.should have_key("NEWFILEUID")
|
|
100
|
+
@ofx.headers["NEWFILEUID"].should be_nil
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
it "should parse headers with CR and without LF" do
|
|
104
|
+
@ofx = OFX::Parser::Base.new(ofx_with_carriage_return)
|
|
105
|
+
@ofx.headers.size.should be(9)
|
|
106
|
+
end
|
|
107
|
+
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
|
+
end
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
require "spec_helper"
|
|
2
|
+
|
|
3
|
+
describe OFX do
|
|
4
|
+
describe "#OFX" do
|
|
5
|
+
it "should yield an OFX instance" do
|
|
6
|
+
OFX("spec/fixtures/sample.ofx") do |ofx|
|
|
7
|
+
ofx.class.should == OFX::Parser::OFX102
|
|
8
|
+
end
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
it "should be an OFX instance" do
|
|
12
|
+
OFX("spec/fixtures/sample.ofx") do
|
|
13
|
+
self.class.should == OFX::Parser::OFX102
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
it "should return parser" do
|
|
18
|
+
OFX("spec/fixtures/sample.ofx").class.should == OFX::Parser::OFX102
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
require "spec_helper"
|
|
2
|
+
|
|
3
|
+
describe OFX::SignOn do
|
|
4
|
+
before do
|
|
5
|
+
@ofx = OFX::Parser::Base.new("spec/fixtures/creditcard.ofx")
|
|
6
|
+
@parser = @ofx.parser
|
|
7
|
+
@sign_on = @parser.sign_on
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
describe "sign_on" do
|
|
11
|
+
it "should return language" do
|
|
12
|
+
@sign_on.language.should == "ENG"
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
it "should return Financial Institution ID" do
|
|
16
|
+
@sign_on.fi_id.should == "24909"
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
it "should return Financial Institution Name" do
|
|
20
|
+
@sign_on.fi_name.should == "Citigroup"
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
it "should return status" do
|
|
24
|
+
@sign_on.status.should be_a(OFX::Status)
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|