zilverline-mt940 1.0 → 2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (52) hide show
  1. checksums.yaml +8 -8
  2. data/Gemfile.lock +1 -1
  3. data/README.md +5 -4
  4. data/lib/mt940.rb +1 -6
  5. data/lib/mt940/version.rb +2 -2
  6. data/lib/mt940_structured/file_content.rb +46 -0
  7. data/lib/mt940_structured/header.rb +30 -0
  8. data/lib/mt940_structured/mt940_structured.rb +8 -0
  9. data/lib/mt940_structured/parser.rb +18 -0
  10. data/lib/mt940_structured/parsers/abnamro/abnamro.rb +5 -0
  11. data/lib/mt940_structured/parsers/abnamro/parser.rb +15 -0
  12. data/lib/mt940_structured/parsers/abnamro/transaction_parser.rb +55 -0
  13. data/lib/mt940_structured/parsers/balance_parser.rb +12 -0
  14. data/lib/mt940_structured/parsers/bank_statement_parser.rb +59 -0
  15. data/lib/mt940_structured/parsers/base.rb +34 -0
  16. data/lib/mt940_structured/parsers/date_parser.rb +7 -0
  17. data/lib/mt940_structured/parsers/default_line61_parser.rb +25 -0
  18. data/lib/mt940_structured/parsers/iban_support.rb +15 -0
  19. data/lib/mt940_structured/parsers/ing/ing.rb +7 -0
  20. data/lib/mt940_structured/parsers/ing/parser.rb +18 -0
  21. data/lib/mt940_structured/parsers/ing/structured_transaction_parser.rb +50 -0
  22. data/lib/mt940_structured/parsers/ing/transaction_parser.rb +31 -0
  23. data/lib/mt940_structured/parsers/ing/types.rb +26 -0
  24. data/lib/mt940_structured/parsers/parsers.rb +16 -0
  25. data/lib/mt940_structured/parsers/rabobank/parser.rb +13 -0
  26. data/lib/mt940_structured/parsers/rabobank/rabobank.rb +8 -0
  27. data/lib/mt940_structured/parsers/rabobank/structured_transaction_parser.rb +41 -0
  28. data/lib/mt940_structured/parsers/rabobank/transaction_parser.rb +29 -0
  29. data/lib/mt940_structured/parsers/rabobank/types.rb +714 -0
  30. data/lib/mt940_structured/parsers/structured_description_parser.rb +12 -0
  31. data/lib/mt940_structured/parsers/tridios/parser.rb +14 -0
  32. data/lib/mt940_structured/parsers/tridios/transaction_parser.rb +23 -0
  33. data/lib/mt940_structured/parsers/tridios/triodos.rb +5 -0
  34. data/spec/fixtures/ing/eu_incasso.txt +17 -0
  35. data/spec/fixtures/ing/eu_incasso_foreign_transaction.txt +17 -0
  36. data/spec/fixtures/ing/failing.txt +18 -0
  37. data/spec/mt940_abnamro_spec.rb +18 -6
  38. data/spec/mt940_ing_spec.rb +78 -2
  39. data/spec/mt940_rabobank_spec.rb +11 -11
  40. data/spec/mt940_structured/file_content_spec.rb +77 -0
  41. data/spec/mt940_structured/header_spec.rb +32 -0
  42. data/spec/mt940_structured/parsers/rabobank/bank_statement_parser_spec.rb +32 -0
  43. data/spec/mt940_triodos_spec.rb +1 -1
  44. data/spec/mt940_two_accounts_spec.rb +1 -1
  45. metadata +41 -9
  46. data/lib/mt940/banks/abnamro.rb +0 -76
  47. data/lib/mt940/banks/ing.rb +0 -84
  48. data/lib/mt940/banks/rabobank.rb +0 -770
  49. data/lib/mt940/banks/triodos.rb +0 -20
  50. data/lib/mt940/base.rb +0 -165
  51. data/lib/mt940/structured_format.rb +0 -16
  52. data/spec/mt940_base_spec.rb +0 -48
@@ -1,20 +0,0 @@
1
- class MT940::Triodos < MT940::Base
2
-
3
- def self.determine_bank(*args)
4
- self if args[0].match(/^:20:/) && args[1] && args[1].match(/^:25:TRIODOSBANK/)
5
- end
6
-
7
- def parse_tag_86
8
- if !@tag86 && @line.match(/^:86:\s?(.*)\Z/m)
9
- @tag86 = true
10
- temp_description = $1.gsub(/\n/, ' ').gsub(/>\d{2}/, '').strip
11
- if temp_description.match(/^\d+(\d{9})(.*)$/)
12
- @transaction.contra_account = $1.rjust(9, '000000000')
13
- @transaction.description = $2.strip
14
- else
15
- @transaction.description = temp_description
16
- end
17
- end
18
- end
19
-
20
- end
@@ -1,165 +0,0 @@
1
- module MT940
2
-
3
- class Base
4
-
5
- MT_940_TAG_LINE = /^:(\d{2}(F|C)?):/
6
-
7
- attr_accessor :bank, :opening_balance, :opening_date
8
-
9
- def self.parse_mt940(file)
10
- file = File.open(file) if file.is_a?(String)
11
- if file.is_a?(File) || file.is_a?(Tempfile)
12
- first_line = file.readline
13
- second_line = file.readline unless file.eof?
14
- klass = determine_bank(first_line, second_line)
15
- file.rewind
16
- instance = klass.new(file)
17
- file.close
18
- instance.parse
19
- else
20
- raise ArgumentError.new('No file is given!')
21
- end
22
- end
23
-
24
- def parse
25
- @tag86 = false
26
- @lines.each do |line|
27
- @line = line
28
- @line.match(MT_940_TAG_LINE) ? send("parse_tag_#{$1}".to_sym) : parse_line
29
- end
30
- @bank_statements
31
- end
32
-
33
- protected
34
- def parse_description_after_tag(description_parts, tag)
35
- description_start_index = description_parts.index { |part| part == tag }
36
- if description_start_index
37
- description_parts[description_start_index + 1].gsub(/\r|\n/, '')
38
- else
39
- ''
40
- end
41
- end
42
-
43
-
44
- private
45
-
46
- def self.determine_bank(*args)
47
- Dir.foreach(File.dirname(__FILE__) + '/banks/') do |file|
48
- if file.match(/\.rb$/)
49
- klass = eval(file.gsub(/\.rb$/, '').capitalize)
50
- bank = klass.determine_bank(*args)
51
- return bank if bank
52
- end
53
- end
54
- self
55
- end
56
-
57
- def initialize(file)
58
- @bank_statements = {}
59
- @transactions = []
60
- @bank = self.class.to_s.split('::').last
61
- @bank = 'Unknown' if @bank == 'Base'
62
- temp_lines = file.readlines
63
- @lines = []
64
- index_of_temp_lines = 0
65
- index_in_lines = 0
66
- while index_of_temp_lines < temp_lines.size do
67
- line = temp_lines[index_of_temp_lines].encode('UTF-8', 'binary', :invalid => :replace, :undef => :replace) # remove invalid chars
68
- if mt_940_start_line?(line)
69
- @lines << line
70
- index_in_lines+=1
71
- else
72
- @lines[index_in_lines-1] += line
73
- end
74
- index_of_temp_lines+=1
75
- end
76
- end
77
-
78
- def mt_940_start_line?(line)
79
- line.match /^:?\d{2}(\D?|\d?):?.*$/
80
- end
81
-
82
- def parse_tag_25
83
- @line.gsub!('.', '')
84
- case @line
85
- when /^:\d{2}:NL/
86
- @bank_account_iban = @line[4, 18]
87
- @bank_account = @bank_account_iban.strip.split(//).last(10).join.sub(/^[0]*/,"")
88
- @is_structured_format = true
89
- when /^:\d{2}:\D*(\d*)/
90
- @bank_account = $1.gsub(/\D/, '').gsub(/^0+/, '')
91
- @is_structured_format = false
92
- else
93
- raise "Unknown format for tag 25: #{@line}"
94
- end
95
- @bank_statements[@bank_account] ||= []
96
- @tag86 = false
97
- end
98
-
99
- def parse_tag_28
100
- @bank_statement = BankStatement.new([], @bank_account, @bank_account_iban, 0, nil, nil)
101
- @bank_statements[@bank_account] << @bank_statement
102
- end
103
-
104
- alias_method :parse_tag_28C, :parse_tag_28
105
-
106
- def parse_tag_60F
107
- @currency = @line[12..14]
108
- balance_date = parse_date(@line[6..11])
109
-
110
- type = @line[5] == 'D' ? -1 : 1
111
- amount = @line[15..-1].gsub(",", ".").to_f * type
112
- @bank_statement.previous_balance = Balance.new(amount, balance_date, @currency)
113
- end
114
-
115
- def parse_tag_62F
116
- @currency = @line[12..14]
117
- balance_date = parse_date(@line[6..11])
118
-
119
- type = @line[5] == 'D' ? -1 : 1
120
- amount = @line[15..-1].gsub(",", ".").to_f * type
121
-
122
- @bank_statement.new_balance = Balance.new(amount, balance_date, @currency)
123
- @tag86 = false
124
- end
125
-
126
- def parse_tag_61
127
- if @line.match(/^:61:(\d{6})(C|D)(\d+),(\d{0,2})/)
128
- type = $2 == 'D' ? -1 : 1
129
- @transaction = MT940::Transaction.new(:bank_account => @bank_account, :amount => type * ($3 + '.' + $4).to_f, :bank => @bank, :currency => @currency)
130
- @transaction.date = parse_date($1)
131
- @bank_statement.transactions << @transaction
132
- @tag86 = false
133
- end
134
- end
135
-
136
- def parse_tag_86
137
- if !@tag86 && @line.match(/^:86:\s?(.*)\Z/m)
138
- @tag86 = true
139
- @transaction.description = $1.gsub(/\n/, ' ').gsub(/>\d{2}/, '').strip
140
- parse_contra_account
141
- end
142
- end
143
-
144
- def parse_line
145
- if @tag86 && @transaction.description
146
- @transaction.description.lstrip!
147
- @transaction.description += ' ' + @line.gsub(/\n/, ' ').gsub(/>\d{2}\s*/, '').gsub(/\-XXX/, '').gsub(/-$/, '').strip
148
- @transaction.description.strip!
149
- end
150
- end
151
-
152
- def parse_date(string)
153
- Date.new(2000 + string[0..1].to_i, string[2..3].to_i, string[4..5].to_i) if string
154
- end
155
-
156
- def parse_contra_account
157
- end
158
-
159
- #Fail silently
160
- def method_missing(*args)
161
- end
162
-
163
- end
164
-
165
- end
@@ -1,16 +0,0 @@
1
- module MT940::StructuredFormat
2
- def parse_line
3
- super unless @skip_parse_line
4
- end
5
-
6
- def read_all_description_lines!
7
- @skip_parse_line = true
8
- index = @lines.index(@line)
9
- @lines[index+1..-1].each do |line|
10
- break if line.match MT940::Base::MT_940_TAG_LINE
11
- @transaction.description.lstrip!
12
- @transaction.description += line.gsub(/\n/, '').gsub(/>\d{2}\s*/, '').gsub(/\-XXX/, '').gsub(/-$/, '').strip
13
- @transaction.description.strip!
14
- end
15
- end
16
- end
@@ -1,48 +0,0 @@
1
- require_relative 'spec_helper'
2
-
3
- describe "Base" do
4
-
5
- context 'MT940::Base' do
6
- it 'read the transactions with the filename of the MT940 file' do
7
- file_name = File.dirname(__FILE__) + '/fixtures/ing.txt'
8
- @transactions = MT940::Base.parse_mt940(file_name)["1234567"].flat_map(&:transactions)
9
- @transactions.size.should == 6
10
- end
11
-
12
- it 'read the transactions with the handle to the mt940 file itself' do
13
- file_name = File.dirname(__FILE__) + '/fixtures/ing.txt'
14
- file = File.open(file_name)
15
- @transactions = MT940::Base.parse_mt940(file)["1234567"].flat_map(&:transactions)
16
- @transactions.size.should == 6
17
- end
18
-
19
- #Tempfile is used by Paperclip, so the following will work:
20
- #MT940::Base.transactions(@mt940_file.attachment.to_file)
21
- it 'read the transactions with the handle of a Tempfile' do
22
- file = Tempfile.new('temp')
23
- file.write(':940:')
24
- file.rewind
25
- @transactions = MT940::Base.parse_mt940(file)
26
- @transactions.size.should == 0
27
- file.unlink
28
- end
29
-
30
- it 'raise an exception if the file does not exist' do
31
- file_name = File.dirname(__FILE__) + '/fixtures/123.txt'
32
- expect {MT940::Base.parse_mt940(file_name)}.to raise_exception Errno::ENOENT
33
- end
34
-
35
- it 'raise an ArgumentError if a wrong argument was given' do
36
- expect {MT940::Base.parse_mt940(Hash.new)}.to raise_exception ArgumentError
37
- end
38
- end
39
-
40
- context 'Unknown MT940 file' do
41
- it 'return its bank' do
42
- file_name = File.dirname(__FILE__) + '/fixtures/unknown.txt'
43
- @transactions = MT940::Base.parse_mt940(file_name)["1234567"].flat_map(&:transactions)
44
- @transactions.first.bank.should == 'Unknown'
45
- end
46
- end
47
-
48
- end