salt-parser 0.0.1

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.
Files changed (97) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +11 -0
  3. data/.rspec +1 -0
  4. data/Gemfile +15 -0
  5. data/Gemfile.lock +88 -0
  6. data/README.rdoc +39 -0
  7. data/Rakefile +7 -0
  8. data/lib/ofx/account.rb +28 -0
  9. data/lib/ofx/accounts.rb +9 -0
  10. data/lib/ofx/balance.rb +15 -0
  11. data/lib/ofx/builder.rb +61 -0
  12. data/lib/ofx/dependencies.rb +13 -0
  13. data/lib/ofx/parser/base.rb +366 -0
  14. data/lib/ofx/parser/ofx102.rb +28 -0
  15. data/lib/ofx/parser/ofx211.rb +21 -0
  16. data/lib/ofx/sign_on.rb +18 -0
  17. data/lib/ofx/transaction.rb +28 -0
  18. data/lib/qif/account.rb +19 -0
  19. data/lib/qif/accounts.rb +54 -0
  20. data/lib/qif/builder.rb +37 -0
  21. data/lib/qif/dependencies.rb +8 -0
  22. data/lib/qif/parser.rb +68 -0
  23. data/lib/qif/transaction.rb +28 -0
  24. data/lib/salt-parser/accounts.rb +11 -0
  25. data/lib/salt-parser/base.rb +19 -0
  26. data/lib/salt-parser/builder.rb +24 -0
  27. data/lib/salt-parser/errors.rb +14 -0
  28. data/lib/salt-parser/version.rb +8 -0
  29. data/salt-parser.gemspec +24 -0
  30. data/spec/ofx/account_spec.rb +97 -0
  31. data/spec/ofx/accounts_response_spec.rb +45 -0
  32. data/spec/ofx/accounts_spec.rb +34 -0
  33. data/spec/ofx/balance_spec.rb +32 -0
  34. data/spec/ofx/builder_spec.rb +136 -0
  35. data/spec/ofx/error_request_spec.rb +37 -0
  36. data/spec/ofx/fixtures/accounts_partial.ofx +52 -0
  37. data/spec/ofx/fixtures/accounts_request.ofx +11 -0
  38. data/spec/ofx/fixtures/accounts_response.ofx +109 -0
  39. data/spec/ofx/fixtures/avatar.gif +0 -0
  40. data/spec/ofx/fixtures/bb.ofx +700 -0
  41. data/spec/ofx/fixtures/credit_card_response.ofx +52 -0
  42. data/spec/ofx/fixtures/creditcard.ofx +79 -0
  43. data/spec/ofx/fixtures/creditcard_transactions_request.ofx +11 -0
  44. data/spec/ofx/fixtures/creditcards_partial.ofx +85 -0
  45. data/spec/ofx/fixtures/date_missing.ofx +73 -0
  46. data/spec/ofx/fixtures/empty_balance.ofx +44 -0
  47. data/spec/ofx/fixtures/invalid_version.ofx +308 -0
  48. data/spec/ofx/fixtures/investment_transactions_response.ofx +108 -0
  49. data/spec/ofx/fixtures/investment_transactions_response2.ofx +200 -0
  50. data/spec/ofx/fixtures/investments_with_mkval.ofx +99 -0
  51. data/spec/ofx/fixtures/missing_headers.ofx +47 -0
  52. data/spec/ofx/fixtures/mixed_accountinfo_response.ofx +58 -0
  53. data/spec/ofx/fixtures/ms_money.ofx +52 -0
  54. data/spec/ofx/fixtures/request_error.ofx +39 -0
  55. data/spec/ofx/fixtures/request_error2.ofx +39 -0
  56. data/spec/ofx/fixtures/request_error3.ofx +36 -0
  57. data/spec/ofx/fixtures/sample_examples/sample_401K_loan.qfx +651 -0
  58. data/spec/ofx/fixtures/sample_examples/sample_banking.qbo +258 -0
  59. data/spec/ofx/fixtures/sample_examples/sample_banking.qfx +258 -0
  60. data/spec/ofx/fixtures/sample_examples/sample_banking_multiacct.qfx +284 -0
  61. data/spec/ofx/fixtures/sample_examples/sample_credit_card.qfx +257 -0
  62. data/spec/ofx/fixtures/sample_examples/sample_investment.qfx +654 -0
  63. data/spec/ofx/fixtures/transactions_empty.ofx +60 -0
  64. data/spec/ofx/fixtures/utf8.ofx +65 -0
  65. data/spec/ofx/fixtures/v102.ofx +314 -0
  66. data/spec/ofx/fixtures/v202.ofx +22 -0
  67. data/spec/ofx/fixtures/v211.ofx +85 -0
  68. data/spec/ofx/investment_accounts_spec.rb +70 -0
  69. data/spec/ofx/ofx102_spec.rb +44 -0
  70. data/spec/ofx/ofx211_spec.rb +68 -0
  71. data/spec/ofx/ofx_parser_spec.rb +100 -0
  72. data/spec/ofx/sign_on_spec.rb +49 -0
  73. data/spec/ofx/transaction_spec.rb +157 -0
  74. data/spec/qif/account_spec.rb +42 -0
  75. data/spec/qif/fixtures/3_records_ddmmyy.qif +19 -0
  76. data/spec/qif/fixtures/3_records_ddmmyyyy.qif +19 -0
  77. data/spec/qif/fixtures/3_records_dmyy.qif +19 -0
  78. data/spec/qif/fixtures/3_records_invalid_header.qif +20 -0
  79. data/spec/qif/fixtures/3_records_mdyy.qif +19 -0
  80. data/spec/qif/fixtures/3_records_mmddyy.qif +19 -0
  81. data/spec/qif/fixtures/3_records_mmddyyyy.qif +19 -0
  82. data/spec/qif/fixtures/3_records_spaced.qif +19 -0
  83. data/spec/qif/fixtures/bank_account.qif +19 -0
  84. data/spec/qif/fixtures/empty_body.qif +1 -0
  85. data/spec/qif/fixtures/empty_header.qif +18 -0
  86. data/spec/qif/fixtures/incompatible_date_formats.qif +13 -0
  87. data/spec/qif/fixtures/invalid_date_format.qif +7 -0
  88. data/spec/qif/fixtures/not_a_QIF_file.txt +3 -0
  89. data/spec/qif/fixtures/quicken_non_investement_account.qif +30 -0
  90. data/spec/qif/fixtures/unknown_account.qif +20 -0
  91. data/spec/qif/fixtures/various_date_format.qif +19 -0
  92. data/spec/qif/fixtures/with_categories_list.qif +8669 -0
  93. data/spec/qif/parser_spec.rb +156 -0
  94. data/spec/qif/transaction_spec.rb +18 -0
  95. data/spec/spec_helper.rb +37 -0
  96. data/spec/support/fixture.rb +9 -0
  97. metadata +208 -0
@@ -0,0 +1,28 @@
1
+ module SaltParser
2
+ module Ofx
3
+ module Parser
4
+ class OFX102 < SaltParser::Ofx::Parser::Base
5
+ VERSION = "1.0.2"
6
+
7
+ def self.parse_headers(header_text)
8
+ # TODO: refactor
9
+ # Change single CR's to LF's to avoid issues with some banks
10
+ header_text.gsub!(/\r(?!\n)/, "\n")
11
+
12
+ # Parse headers. When value is NONE, convert it to nil.
13
+ headers = header_text.to_enum(:each_line).inject({}) do |memo, line|
14
+ _, key, value = *line.match(/^(.*?):(.*?)\s*(\r?\n)*$/)
15
+
16
+ unless key.nil?
17
+ memo[key] = value == "NONE" ? nil : value
18
+ end
19
+
20
+ memo
21
+ end
22
+
23
+ return headers unless headers.empty?
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,21 @@
1
+ module SaltParser
2
+ module Ofx
3
+ module Parser
4
+ class OFX211 < SaltParser::Ofx::Parser::Base
5
+ VERSION = "2.1.1"
6
+
7
+ def self.parse_headers(header_text)
8
+ Nokogiri::XML(header_text).children.each do |element|
9
+ if element.name == "OFX"
10
+ headers = element.text.gsub("\"",'')
11
+ .split(/\s+/)
12
+ .map { |el| el.split("=") }
13
+ .flatten
14
+ return Hash[*headers]
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,18 @@
1
+ module SaltParser
2
+ module Ofx
3
+ class SignOn < SaltParser::Base
4
+ attr_accessor :language, :fi_id, :fi_name, :code, :severity, :message
5
+
6
+ def to_hash
7
+ {
8
+ :language => language,
9
+ :fi_id => fi_id,
10
+ :fi_name => fi_name,
11
+ :code => code,
12
+ :severity => severity,
13
+ :message => message
14
+ }
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,28 @@
1
+ module SaltParser
2
+ module Ofx
3
+ class Transaction < SaltParser::Base
4
+ attr_accessor :amount, :amount_in_pennies, :check_number, :fit_id,
5
+ :memo, :name, :payee, :posted_at, :ref_number, :type,
6
+ :sic, :units, :unit_price, :account_id
7
+
8
+ def to_hash
9
+ {
10
+ :amount => amount,
11
+ :amount_in_pennies => amount_in_pennies,
12
+ :check_number => check_number,
13
+ :fit_id => fit_id,
14
+ :memo => memo,
15
+ :name => name,
16
+ :payee => payee,
17
+ :posted_at => posted_at,
18
+ :ref_number => ref_number,
19
+ :type => type,
20
+ :sic => sic,
21
+ :units => units,
22
+ :unit_price => unit_price,
23
+ :account_id => account_id
24
+ }
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,19 @@
1
+ module SaltParser
2
+ module Qif
3
+ class Account < SaltParser::Base
4
+ attr_accessor :name, :type, :transactions
5
+
6
+ def identifier
7
+ name
8
+ end
9
+
10
+ def to_hash
11
+ {
12
+ :name => name,
13
+ :type => type,
14
+ :transactions => transactions.map(&:to_hash)
15
+ }
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,54 @@
1
+ module SaltParser
2
+ module Qif
3
+ class Accounts < SaltParser::Accounts
4
+ SUPPORTED_ACCOUNTS = {
5
+ "!Type:Bank" => {
6
+ "type" => "bank_account",
7
+ "name" => "Bank account"
8
+ },
9
+ "!Type:Cash" => {
10
+ "type" => "cash",
11
+ "name" => "Cash account"
12
+ },
13
+ "!Type:CCard" => {
14
+ "type" => "credit_card",
15
+ "name" => "Credit card account"
16
+ },
17
+ "!Type:Oth A" => {
18
+ "type" => "asset",
19
+ "name" => "Asset account"
20
+ },
21
+ "!Type:Oth L" => {
22
+ "type" => "liability_account",
23
+ "name" => "Liability account"
24
+ }
25
+ }
26
+ SUPPORTED_ACCOUNTS.default = {
27
+ "type" => "account",
28
+ "name" => "account"
29
+ }
30
+ NOT_SUPPORTED_ACCOUNTS = {
31
+ "!Account" => {
32
+ "type" => "account_list",
33
+ "name" => "Account list or which account follows"
34
+ },
35
+ "!Type:Cat" => {
36
+ "type" => "category_list",
37
+ "name" => "Category list"
38
+ },
39
+ "!Type:Class" => {
40
+ "type" => "class_list",
41
+ "name" => "Class list"
42
+ },
43
+ "!Type:Memorized" => {
44
+ "type" => "memorized_transaction_list",
45
+ "name" => "Memorized transaction list"
46
+ },
47
+ "!Type:Invoice" => {
48
+ "type" => "invoice",
49
+ "name" => "Invoice (Quicken for Business only)"
50
+ }
51
+ }
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,37 @@
1
+ module SaltParser
2
+ module Qif
3
+ class Builder < SaltParser::Builder
4
+
5
+ def initialize(resource, date_format="%m/%d/%Y")
6
+ resource = open_resource(resource)
7
+ resource.rewind
8
+
9
+ @content = convert_to_utf8(resource.read)
10
+ prepare(content)
11
+
12
+ @parser = Parser.new(:headers => headers, :body => body, :date_format => date_format)
13
+ end
14
+
15
+ private
16
+
17
+ def prepare(content)
18
+ # ignore internal Quicken information
19
+ # http://en.wikipedia.org/wiki/Quicken_Interchange_Format#Header_line
20
+ split_content = content.split(/(^!.+)/).reject(&:blank?).map(&:strip)
21
+ split_content.each_slice(2) do |slice|
22
+ if slice.length == 1
23
+ @body = slice.first
24
+ else
25
+ next if Qif::Accounts::NOT_SUPPORTED_ACCOUNTS.keys.include?(slice.first)
26
+ @headers = slice.first
27
+ @body = slice.last
28
+ end
29
+ end
30
+
31
+ if body.nil? or body.match(/(^!.+)/)
32
+ raise SaltParser::Error::EmptyFileBody
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,8 @@
1
+ require "date"
2
+ require "chronic"
3
+
4
+ require_relative "builder"
5
+ require_relative "account"
6
+ require_relative "accounts"
7
+ require_relative "transaction"
8
+ require_relative "parser"
data/lib/qif/parser.rb ADDED
@@ -0,0 +1,68 @@
1
+ module SaltParser
2
+ module Qif
3
+ class Parser
4
+ attr_reader :headers, :body, :accounts, :date_format
5
+
6
+ def initialize(options = {})
7
+ @headers = options[:headers].try(:chomp)
8
+ @body = options[:body]
9
+ @date_format = options[:date_format]
10
+ @accounts = Qif::Accounts.new
11
+ parse_account
12
+ end
13
+
14
+ def to_hash
15
+ { :accounts => accounts.to_hash }
16
+ end
17
+
18
+ def parse_account
19
+ @accounts << Qif::Account.new({
20
+ :name => Qif::Accounts::SUPPORTED_ACCOUNTS[headers]["name"],
21
+ :type => Qif::Accounts::SUPPORTED_ACCOUNTS[headers]["type"],
22
+ :transactions => build_transactions
23
+ })
24
+ end
25
+
26
+ def build_transactions
27
+ transactions_array = body.split("^").reject(&:blank?)
28
+ check_dates(transactions_array)
29
+
30
+ transactions_array.each_with_object([]) do |transaction, transactions|
31
+ transaction_hash = build_transaction_hash(transaction.split("\n"))
32
+ transactions << Qif::Transaction.new(transaction_hash) unless transaction_hash.empty?
33
+ end
34
+ end
35
+
36
+ def build_transaction_hash(rows)
37
+ hash = {}
38
+ rows.map do |row|
39
+ type = Qif::Transaction::SUPPORTED_FIELDS[row[0].try(:upcase)]
40
+ next unless type
41
+ hash[type] = type == :date ? parse_date(row[1..-1]) : row[1..-1].strip
42
+ end
43
+ hash[:date].nil? ? {} : hash
44
+ end
45
+
46
+ def parse_date(row)
47
+ date = Date.strptime(row, date_format)
48
+ raise ArgumentError if date.year < 1900
49
+ date.as_json
50
+ rescue ArgumentError => error
51
+ Chronic.parse(row, :endian_precedence => [:middle, :little]).to_date.as_json
52
+ end
53
+
54
+ def check_dates(transactions_array)
55
+ dates = transactions_array.map{ |transaction| transaction.split("\n") }
56
+ .flatten
57
+ .select{ |line| line.match(/^D/) }
58
+ .map{ |line| line[1..-1] }
59
+
60
+ dates.each do |row|
61
+ unless Chronic.parse(row)
62
+ raise SaltParser::Error::UnsupportedDateFormat.new
63
+ end
64
+ end
65
+ end
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,28 @@
1
+ module SaltParser
2
+ module Qif
3
+ class Transaction < SaltParser::Base
4
+ SUPPORTED_FIELDS = {
5
+ "D" => :date , # Date
6
+ "T" => :amount , # Amount
7
+ "C" => :status , # Cleared status
8
+ "N" => :number , # Num (check or reference number)
9
+ "P" => :payee , # Payee
10
+ "M" => :memo , # Memo
11
+ "L" => :category # Category (Category/Subcategory/Transfer/Class)
12
+ }
13
+ SUPPORTED_FIELDS.values.each{ |field| attr_accessor field }
14
+
15
+ def to_hash
16
+ {
17
+ :date => date,
18
+ :amount => amount,
19
+ :status => status,
20
+ :number => number,
21
+ :payee => payee,
22
+ :memo => memo,
23
+ :category => category
24
+ }
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,11 @@
1
+ module SaltParser
2
+ class Accounts < Array
3
+ def find(identifier)
4
+ detect { |account| account.identifier == identifier }
5
+ end
6
+
7
+ def to_hash
8
+ map { |account| account.to_hash }
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,19 @@
1
+ require "active_support"
2
+ require "active_support/core_ext"
3
+
4
+ module SaltParser
5
+ class Base
6
+ def initialize(attrs)
7
+ attrs.each do |key, value|
8
+ send("#{key}=", value)
9
+ end
10
+ end
11
+ end
12
+ end
13
+
14
+ require_relative "accounts"
15
+ require_relative "errors"
16
+ require_relative "builder"
17
+
18
+ require "ofx/dependencies"
19
+ require "qif/dependencies"
@@ -0,0 +1,24 @@
1
+ module SaltParser
2
+ class Builder
3
+ attr_reader :headers, :body, :content, :parser
4
+
5
+ private
6
+
7
+ def open_resource(resource)
8
+ if resource.respond_to?(:read)
9
+ resource
10
+ else
11
+ open(resource)
12
+ end
13
+ rescue Exception
14
+ StringIO.new(resource)
15
+ end
16
+
17
+ def convert_to_utf8(string)
18
+ return string if Kconv.isutf8(string)
19
+ string.encode(Encoding::UTF_8.to_s, Encoding::ISO_8859_1.to_s)
20
+ rescue Exception
21
+ raise SaltParser::Error::InvalidEncoding
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,14 @@
1
+ module SaltParser
2
+ module Error
3
+ class EmptyFileBody < StandardError; end
4
+ class InvalidEncoding < StandardError; end
5
+ class ParseError < StandardError
6
+ AMOUNT = "Error while parsing numeric field."
7
+ TIME = "Error while parsing time field."
8
+ FLOAT = "Error while parsing float field."
9
+ end
10
+ class RequestError < StandardError; end
11
+ class UnsupportedDateFormat < StandardError; end
12
+ class UnsupportedFileError < StandardError; end
13
+ end
14
+ end
@@ -0,0 +1,8 @@
1
+ module SaltParser
2
+ module Version
3
+ MAJOR = 0
4
+ MINOR = 0
5
+ PATCH = 1
6
+ STRING = "#{MAJOR}.#{MINOR}.#{PATCH}"
7
+ end
8
+ end
@@ -0,0 +1,24 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "salt-parser/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "salt-parser"
7
+ s.version = SaltParser::Version::STRING
8
+ s.platform = Gem::Platform::RUBY
9
+ s.authors = ["saltedge team"]
10
+ s.email = ["support@saltedge.com"]
11
+ s.homepage = "http://example.com"
12
+ s.summary = "Gem for parsing OFX, HBCI, QIF and SWIFT formats."
13
+ s.description = "Gem for parsing OFX, HBCI, QIF and SWIFT formats."
14
+ s.files = `git ls-files`.split("\n")
15
+ s.test_files = `git ls-files -- {spec}/*`.split("\n")
16
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |file| File.basename(f) }
17
+ s.require_paths = ["lib"]
18
+
19
+ s.add_dependency "nokogiri"
20
+ s.add_development_dependency "rspec", "~> 3.0"
21
+ s.add_development_dependency 'bundler', '~> 1.3'
22
+ s.add_development_dependency "rake"
23
+ s.add_development_dependency "pry-byebug"
24
+ end
@@ -0,0 +1,97 @@
1
+ require "spec_helper"
2
+
3
+ describe SaltParser::Ofx::Account do
4
+ let(:ofx) { SaltParser::Ofx::Builder.new("spec/ofx/fixtures/v102.ofx") }
5
+ let(:parser) { ofx.parser }
6
+ let(:account) { parser.accounts.first }
7
+ let(:hash) { account.to_hash }
8
+
9
+ describe "account" do
10
+ context "Bank account" do
11
+ it "should return currency" do
12
+ account.currency.should == "BRL"
13
+ hash[:currency].should == account.currency
14
+ end
15
+
16
+ it "should return bank id" do
17
+ account.bank_id.should == "0356"
18
+ hash[:bank_id].should == account.bank_id
19
+ end
20
+
21
+ it "should return id" do
22
+ account.id.should == "03227113109"
23
+ hash[:id].should == account.id
24
+ end
25
+
26
+ it "should return type" do
27
+ account.type.should == :checking
28
+ hash[:type].should == account.type
29
+ end
30
+
31
+ it "should return transactions" do
32
+ account.transactions.should be_a_kind_of(Array)
33
+ account.transactions.size.should == 36
34
+ hash[:transactions].should be_a_kind_of(Array)
35
+ hash[:transactions].size.should == account.transactions.size
36
+ hash[:transactions].first.should == account.transactions.first.to_hash
37
+ end
38
+
39
+ it "should return balance" do
40
+ account.balance.amount.should == 598.44
41
+ hash[:balance][:amount].should == account.balance.amount
42
+ end
43
+
44
+ it "should return balance in pennies" do
45
+ account.balance.amount_in_pennies.should == 59844
46
+ hash[:balance][:amount_in_pennies].should == account.balance.amount_in_pennies
47
+ end
48
+
49
+ it "should return balance date" do
50
+ account.balance.posted_at.should == Time.parse("2009-11-01")
51
+ hash[:balance][:posted_at].should == Time.parse("2009-11-01")
52
+ end
53
+
54
+ context "available_balance" do
55
+ it "should return available balance" do
56
+ account.available_balance.amount.should == 1555.99
57
+ hash[:available_balance][:amount].should == account.available_balance.amount
58
+ end
59
+
60
+ it "should return available balance in pennies" do
61
+ account.available_balance.amount_in_pennies.should == 155599
62
+ hash[:available_balance][:amount_in_pennies].should == account.available_balance.amount_in_pennies
63
+ end
64
+
65
+ it "should return available balance date" do
66
+ account.available_balance.posted_at.should == Time.parse("2009-11-01")
67
+ hash[:available_balance][:posted_at].should == account.available_balance.posted_at
68
+ end
69
+
70
+ it "should return nil if AVAILBAL not found" do
71
+ ofx = SaltParser::Ofx::Builder.new("spec/ofx/fixtures/utf8.ofx")
72
+ account = ofx.parser.accounts.first
73
+ account.available_balance.should be_nil
74
+ end
75
+ end
76
+ end
77
+
78
+ context "Credit Card" do
79
+ let(:ofx) { SaltParser::Ofx::Builder.new("spec/ofx/fixtures/v211.ofx") }
80
+ let(:account) { parser.accounts.last }
81
+
82
+ it "should return id" do
83
+ account.id.should == "123412341234"
84
+ end
85
+
86
+ it "should return currency" do
87
+ account.currency.should == "USD"
88
+ end
89
+ end
90
+
91
+ context "#to_hash" do
92
+ it "should return Hash" do
93
+ hash.should be_a_kind_of(Hash)
94
+ end
95
+ end
96
+ end
97
+ end
@@ -0,0 +1,45 @@
1
+ require "spec_helper"
2
+
3
+ describe "Bank accounts response" do
4
+ let(:ofx) { SaltParser::Ofx::Builder.new("spec/ofx/fixtures/accounts_response.ofx") }
5
+ let(:parser) { ofx.parser }
6
+ let(:accounts) { parser.accounts }
7
+
8
+ describe "accounts" do
9
+ it "should parse bank account from bank response" do
10
+ accounts.size.should == 5
11
+ accounts.first.to_hash.should == {
12
+ :bank_id => "123456789",
13
+ :id => "1234567890",
14
+ :name => "SILVERWIZ SAVINGS",
15
+ :broker_id => nil,
16
+ :type => :savings,
17
+ :units => nil,
18
+ :unit_price => nil,
19
+ :currency => "",
20
+ :balance => nil,
21
+ :transactions => [],
22
+ :available_balance => nil
23
+ }
24
+ end
25
+ end
26
+
27
+ describe "sign_on" do
28
+ it "should parse sign_on data from bank response" do
29
+ parser.sign_on.to_hash.should == {
30
+ :language => "ENG",
31
+ :fi_id => "10898",
32
+ :fi_name => "B1",
33
+ :code => "0",
34
+ :severity => "INFO",
35
+ :message => "SUCCESS"
36
+ }
37
+ end
38
+ end
39
+
40
+ describe "errors" do
41
+ it "should not have any errors" do
42
+ parser.errors.size.should be_zero
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,34 @@
1
+ require "spec_helper"
2
+
3
+ describe SaltParser::Ofx::Accounts do
4
+ let(:ofx) { SaltParser::Ofx::Builder.new("spec/ofx/fixtures/v211.ofx") }
5
+ let(:accounts) { ofx.parser.accounts }
6
+ let(:hash) { accounts.to_hash }
7
+
8
+ describe "accounts" do
9
+ it "should return multiple accounts" do
10
+ accounts.size.should == 2
11
+ end
12
+
13
+ describe "#find" do
14
+ it "returns first by id" do
15
+ accounts.find("123456").class.should == SaltParser::Ofx::Account
16
+ end
17
+ end
18
+
19
+ describe "#find_by_transaction" do
20
+ it "returns first by transaction's account_id and it's currency code" do
21
+ account = accounts.first
22
+ transaction = account.transactions.first
23
+ accounts.find_by_transaction(transaction).should == account
24
+ end
25
+ end
26
+
27
+ context "#to_hash" do
28
+ it "should return array of Hashes" do
29
+ hash.should be_a_kind_of(Array)
30
+ hash.first.should be_a_kind_of(Hash)
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,32 @@
1
+ require "spec_helper"
2
+
3
+ describe SaltParser::Ofx::Balance do
4
+ let(:ofx) { SaltParser::Ofx::Builder.new("spec/ofx/fixtures/v102.ofx") }
5
+ let(:parser) { ofx.parser }
6
+ let(:account) { parser.accounts.first }
7
+ let(:balance) { account.balance }
8
+ let(:hash) { balance.to_hash }
9
+
10
+ describe "balance" do
11
+ it "should return amount" do
12
+ balance.amount.should == 598.44
13
+ hash[:amount].should == balance.amount
14
+ end
15
+
16
+ it "should return amount_in_pennies" do
17
+ balance.amount_in_pennies.should == 59844
18
+ hash[:amount_in_pennies].should == balance.amount_in_pennies
19
+ end
20
+
21
+ it "should return posted_at" do
22
+ balance.posted_at.should == Time.parse("2009-11-01")
23
+ hash[:posted_at].should == balance.posted_at
24
+ end
25
+
26
+ context "#to_hash" do
27
+ it "should return Hash" do
28
+ hash.should be_a_kind_of(Hash)
29
+ end
30
+ end
31
+ end
32
+ end