zilverline-mt940 1.0 → 2.0
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 +8 -8
- data/Gemfile.lock +1 -1
- data/README.md +5 -4
- data/lib/mt940.rb +1 -6
- data/lib/mt940/version.rb +2 -2
- data/lib/mt940_structured/file_content.rb +46 -0
- data/lib/mt940_structured/header.rb +30 -0
- data/lib/mt940_structured/mt940_structured.rb +8 -0
- data/lib/mt940_structured/parser.rb +18 -0
- data/lib/mt940_structured/parsers/abnamro/abnamro.rb +5 -0
- data/lib/mt940_structured/parsers/abnamro/parser.rb +15 -0
- data/lib/mt940_structured/parsers/abnamro/transaction_parser.rb +55 -0
- data/lib/mt940_structured/parsers/balance_parser.rb +12 -0
- data/lib/mt940_structured/parsers/bank_statement_parser.rb +59 -0
- data/lib/mt940_structured/parsers/base.rb +34 -0
- data/lib/mt940_structured/parsers/date_parser.rb +7 -0
- data/lib/mt940_structured/parsers/default_line61_parser.rb +25 -0
- data/lib/mt940_structured/parsers/iban_support.rb +15 -0
- data/lib/mt940_structured/parsers/ing/ing.rb +7 -0
- data/lib/mt940_structured/parsers/ing/parser.rb +18 -0
- data/lib/mt940_structured/parsers/ing/structured_transaction_parser.rb +50 -0
- data/lib/mt940_structured/parsers/ing/transaction_parser.rb +31 -0
- data/lib/mt940_structured/parsers/ing/types.rb +26 -0
- data/lib/mt940_structured/parsers/parsers.rb +16 -0
- data/lib/mt940_structured/parsers/rabobank/parser.rb +13 -0
- data/lib/mt940_structured/parsers/rabobank/rabobank.rb +8 -0
- data/lib/mt940_structured/parsers/rabobank/structured_transaction_parser.rb +41 -0
- data/lib/mt940_structured/parsers/rabobank/transaction_parser.rb +29 -0
- data/lib/mt940_structured/parsers/rabobank/types.rb +714 -0
- data/lib/mt940_structured/parsers/structured_description_parser.rb +12 -0
- data/lib/mt940_structured/parsers/tridios/parser.rb +14 -0
- data/lib/mt940_structured/parsers/tridios/transaction_parser.rb +23 -0
- data/lib/mt940_structured/parsers/tridios/triodos.rb +5 -0
- data/spec/fixtures/ing/eu_incasso.txt +17 -0
- data/spec/fixtures/ing/eu_incasso_foreign_transaction.txt +17 -0
- data/spec/fixtures/ing/failing.txt +18 -0
- data/spec/mt940_abnamro_spec.rb +18 -6
- data/spec/mt940_ing_spec.rb +78 -2
- data/spec/mt940_rabobank_spec.rb +11 -11
- data/spec/mt940_structured/file_content_spec.rb +77 -0
- data/spec/mt940_structured/header_spec.rb +32 -0
- data/spec/mt940_structured/parsers/rabobank/bank_statement_parser_spec.rb +32 -0
- data/spec/mt940_triodos_spec.rb +1 -1
- data/spec/mt940_two_accounts_spec.rb +1 -1
- metadata +41 -9
- data/lib/mt940/banks/abnamro.rb +0 -76
- data/lib/mt940/banks/ing.rb +0 -84
- data/lib/mt940/banks/rabobank.rb +0 -770
- data/lib/mt940/banks/triodos.rb +0 -20
- data/lib/mt940/base.rb +0 -165
- data/lib/mt940/structured_format.rb +0 -16
- data/spec/mt940_base_spec.rb +0 -48
data/lib/mt940/banks/triodos.rb
DELETED
@@ -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
|
data/lib/mt940/base.rb
DELETED
@@ -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
|
data/spec/mt940_base_spec.rb
DELETED
@@ -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
|