From ca8344c76b375df7c0fb21052422ffe6eb0866d7 Mon Sep 17 00:00:00 2001 From: Ygor Geurts Date: Fri, 16 Nov 2012 22:48:29 +0100 Subject: [PATCH 01/10] deutsche bank support --- Gemfile | 2 +- Gemfile.lock | 18 ++++++++++++++---- lib/mt940/banks/deutsche_bank.rb | 14 ++++++++++++++ lib/mt940/base.rb | 4 ++-- 4 files changed, 31 insertions(+), 7 deletions(-) create mode 100644 lib/mt940/banks/deutsche_bank.rb diff --git a/Gemfile b/Gemfile index 58c5866..855cf03 100644 --- a/Gemfile +++ b/Gemfile @@ -1,5 +1,5 @@ source "http://rubygems.org" -gem 'rake', '0.8.7' +gem 'rake' gemspec diff --git a/Gemfile.lock b/Gemfile.lock index 27c72da..f6c06ae 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,18 +1,28 @@ PATH remote: . specs: - mt940 (0.6.5) + mt940 (0.6.6) GEM remote: http://rubygems.org/ specs: - rake (0.8.7) - shoulda (2.11.3) + activesupport (3.2.8) + i18n (~> 0.6) + multi_json (~> 1.0) + i18n (0.6.1) + multi_json (1.3.7) + rake (0.9.2.2) + shoulda (3.3.2) + shoulda-context (~> 1.0.1) + shoulda-matchers (~> 1.4.1) + shoulda-context (1.0.1) + shoulda-matchers (1.4.1) + activesupport (>= 3.0.0) PLATFORMS ruby DEPENDENCIES mt940! - rake (= 0.8.7) + rake shoulda diff --git a/lib/mt940/banks/deutsche_bank.rb b/lib/mt940/banks/deutsche_bank.rb new file mode 100644 index 0000000..4e167f3 --- /dev/null +++ b/lib/mt940/banks/deutsche_bank.rb @@ -0,0 +1,14 @@ +class MT940::DeutscheBank < MT940::Abnamro + def self.determine_bank(*args) + self if args[0].match(/DEUTDE/) + end + + def parse_contra_account + if @transaction + if @transaction.description.match(/(.+)\/\/ACCW\/(\d+)\//) + @transaction.contra_account = $2 + @transaction.description = $1 + end + end + end +end diff --git a/lib/mt940/base.rb b/lib/mt940/base.rb index 7e0909c..7fb0370 100644 --- a/lib/mt940/base.rb +++ b/lib/mt940/base.rb @@ -1,3 +1,4 @@ +#encoding: utf-8 module MT940 class Base @@ -5,7 +6,7 @@ class Base attr_accessor :bank def self.transactions(file) - file = File.open(file) if file.is_a?(String) + file = File.open(file) if file.is_a?(String) if file.is_a?(File) || file.is_a?(Tempfile) first_line = file.readline second_line = file.readline unless file.eof? @@ -96,7 +97,6 @@ def parse_contra_account #Fail silently def method_missing(*args) end - end end From 8e17ac73bbbb19d719c277d80570d728037331e0 Mon Sep 17 00:00:00 2001 From: Ygor Geurts Date: Fri, 16 Nov 2012 23:08:41 +0100 Subject: [PATCH 02/10] encoding utf-8 --- lib/mt940.rb | 3 ++- lib/mt940/base.rb | 4 ++-- test/mt940_base_test.rb | 2 +- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/lib/mt940.rb b/lib/mt940.rb index 8a237f3..461e40b 100644 --- a/lib/mt940.rb +++ b/lib/mt940.rb @@ -7,4 +7,5 @@ require 'mt940/banks/ing' require 'mt940/banks/rabobank' require 'mt940/banks/abnamro' -require 'mt940/banks/triodos' \ No newline at end of file +require 'mt940/banks/triodos' +require 'mt940/banks/deutsche_bank' \ No newline at end of file diff --git a/lib/mt940/base.rb b/lib/mt940/base.rb index 7fb0370..3e80494 100644 --- a/lib/mt940/base.rb +++ b/lib/mt940/base.rb @@ -6,7 +6,7 @@ class Base attr_accessor :bank def self.transactions(file) - file = File.open(file) if file.is_a?(String) + file = File.open(file, 'r:utf-8') if file.is_a?(String) if file.is_a?(File) || file.is_a?(Tempfile) first_line = file.readline second_line = file.readline unless file.eof? @@ -34,7 +34,7 @@ def parse def self.determine_bank(*args) Dir.foreach(File.dirname(__FILE__) + '/banks/') do |file| if file.match(/\.rb$/) - klass = eval(file.gsub(/\.rb$/,'').capitalize) + klass = eval(file.gsub(/\.rb$/,'').split('_').map{|e| e.capitalize}.join) bank = klass.determine_bank(*args) return bank if bank end diff --git a/test/mt940_base_test.rb b/test/mt940_base_test.rb index 223bea4..6fffb45 100644 --- a/test/mt940_base_test.rb +++ b/test/mt940_base_test.rb @@ -11,7 +11,7 @@ class TestMt940Base < Test::Unit::TestCase should 'read the transactions with the handle to the mt940 file itself' do file_name = File.dirname(__FILE__) + '/fixtures/ing.txt' - file = File.open(file_name) + file = File.open(file_name, 'r:utf-8') @transactions = MT940::Base.transactions(file) assert_equal 6, @transactions.size end From 8b0b3c58e30fdf99ec58d3adcddec1bfcf91a9c4 Mon Sep 17 00:00:00 2001 From: Ygor Geurts Date: Fri, 16 Nov 2012 23:25:54 +0100 Subject: [PATCH 03/10] parse second line of description for contra account --- lib/mt940/base.rb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/mt940/base.rb b/lib/mt940/base.rb index 3e80494..e54d442 100644 --- a/lib/mt940/base.rb +++ b/lib/mt940/base.rb @@ -84,6 +84,7 @@ def parse_line @transaction.description.lstrip! @transaction.description += ' ' + @line.gsub(/\n/,'').gsub(/>\d{2}\s*/,'').gsub(/\-XXX/,'').gsub(/-$/,'').strip @transaction.description.strip! + parse_contra_account end end @@ -96,6 +97,7 @@ def parse_contra_account #Fail silently def method_missing(*args) + @tag86 = false end end From 6df3be352b6ebd17f3f629c23f1d3a10016d4989 Mon Sep 17 00:00:00 2001 From: Ygor Geurts Date: Fri, 16 Nov 2012 23:32:55 +0100 Subject: [PATCH 04/10] correctly parse contra account form description for db --- lib/mt940/banks/deutsche_bank.rb | 5 +++++ lib/mt940/base.rb | 2 -- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/lib/mt940/banks/deutsche_bank.rb b/lib/mt940/banks/deutsche_bank.rb index 4e167f3..dd69e42 100644 --- a/lib/mt940/banks/deutsche_bank.rb +++ b/lib/mt940/banks/deutsche_bank.rb @@ -11,4 +11,9 @@ def parse_contra_account end end end + + def parse_tag_62 + parse_contra_account + @tag86 = false + end end diff --git a/lib/mt940/base.rb b/lib/mt940/base.rb index e54d442..3e80494 100644 --- a/lib/mt940/base.rb +++ b/lib/mt940/base.rb @@ -84,7 +84,6 @@ def parse_line @transaction.description.lstrip! @transaction.description += ' ' + @line.gsub(/\n/,'').gsub(/>\d{2}\s*/,'').gsub(/\-XXX/,'').gsub(/-$/,'').strip @transaction.description.strip! - parse_contra_account end end @@ -97,7 +96,6 @@ def parse_contra_account #Fail silently def method_missing(*args) - @tag86 = false end end From 3c83f68a053922a0e0cb67aad242be5e93ba888a Mon Sep 17 00:00:00 2001 From: Ygor Geurts Date: Fri, 16 Nov 2012 23:59:23 +0100 Subject: [PATCH 05/10] refactor to allow extraction of contra account from second 86 line --- lib/mt940/banks/abnamro.rb | 4 ++-- lib/mt940/banks/ing.rb | 2 +- lib/mt940/base.rb | 12 ++++++++---- 3 files changed, 11 insertions(+), 7 deletions(-) diff --git a/lib/mt940/banks/abnamro.rb b/lib/mt940/banks/abnamro.rb index 35b8c48..737b117 100644 --- a/lib/mt940/banks/abnamro.rb +++ b/lib/mt940/banks/abnamro.rb @@ -18,9 +18,9 @@ def parse_contra_account if @transaction if @transaction.description.match(/^(GIRO)\s+(\d+)(.+)/) @transaction.contra_account = $2.rjust(9, '000000000') - @transaction.description = $3 + @transaction.description = $3.strip elsif @transaction.description.match(/^(\d{2}.\d{2}.\d{2}.\d{3})(.+)/) - @transaction.description = $2 + @transaction.description = $2.strip @transaction.contra_account = $1.gsub('.','') end end diff --git a/lib/mt940/banks/ing.rb b/lib/mt940/banks/ing.rb index 3e202a1..16b1169 100644 --- a/lib/mt940/banks/ing.rb +++ b/lib/mt940/banks/ing.rb @@ -7,7 +7,7 @@ def self.determine_bank(*args) def parse_contra_account if @transaction && @transaction.description.match(/^\d(\d{9})(.+)/) @transaction.contra_account = $1 - @transaction.description = $2 + @transaction.description = $2.strip end end diff --git a/lib/mt940/base.rb b/lib/mt940/base.rb index 3e80494..452bb5b 100644 --- a/lib/mt940/base.rb +++ b/lib/mt940/base.rb @@ -24,7 +24,7 @@ def parse @tag86 = false @lines.each do |line| @line = line - @line.match(/^:(\d{2}F?):/) ? eval('parse_tag_'+ $1) : parse_line + @line.match(/^:(\d{2}F?):/) ? parse_tag($1) : parse_line end @transactions end @@ -49,6 +49,12 @@ def initialize(file) @lines = file.readlines end + def parse_tag(tag) + @tag86 = false if tag.to_s != '86' + send("parse_tag_#{tag}") + parse_contra_account if @transaction && @transaction.description + end + def parse_tag_25 @line.gsub!('.','') if @line.match(/^:\d{2}:[^\d]*(\d*)/) @@ -72,16 +78,14 @@ def parse_tag_61 end def parse_tag_86 - if !@tag86 && @line.match(/^:86:\s?(.*)$/) + if !@transaction.description && @line.match(/^:86:\s?(.*)$/) @tag86 = true @transaction.description = $1.gsub(/>\d{2}/,'').strip - parse_contra_account end end def parse_line if @tag86 && @transaction.description - @transaction.description.lstrip! @transaction.description += ' ' + @line.gsub(/\n/,'').gsub(/>\d{2}\s*/,'').gsub(/\-XXX/,'').gsub(/-$/,'').strip @transaction.description.strip! end From 680b612a82fb626d34c00d896ce13a35632cf32a Mon Sep 17 00:00:00 2001 From: Ygor Geurts Date: Sat, 17 Nov 2012 11:11:40 +0100 Subject: [PATCH 06/10] make all tests pass --- lib/mt940/banks/deutsche_bank.rb | 7 ++----- lib/mt940/banks/ing.rb | 3 +++ lib/mt940/banks/rabobank.rb | 10 ---------- lib/mt940/banks/triodos.rb | 4 ++-- lib/mt940/base.rb | 22 +++++++++++++--------- lib/mt940/transaction.rb | 2 -- 6 files changed, 20 insertions(+), 28 deletions(-) diff --git a/lib/mt940/banks/deutsche_bank.rb b/lib/mt940/banks/deutsche_bank.rb index dd69e42..ef66b4e 100644 --- a/lib/mt940/banks/deutsche_bank.rb +++ b/lib/mt940/banks/deutsche_bank.rb @@ -1,4 +1,5 @@ class MT940::DeutscheBank < MT940::Abnamro + def self.determine_bank(*args) self if args[0].match(/DEUTDE/) end @@ -7,13 +8,9 @@ def parse_contra_account if @transaction if @transaction.description.match(/(.+)\/\/ACCW\/(\d+)\//) @transaction.contra_account = $2 - @transaction.description = $1 + @transaction.description = $1.strip end end end - def parse_tag_62 - parse_contra_account - @tag86 = false - end end diff --git a/lib/mt940/banks/ing.rb b/lib/mt940/banks/ing.rb index 16b1169..9d6c7ce 100644 --- a/lib/mt940/banks/ing.rb +++ b/lib/mt940/banks/ing.rb @@ -11,4 +11,7 @@ def parse_contra_account end end + def parse_tag_86? + @transaction.description.nil? + end end \ No newline at end of file diff --git a/lib/mt940/banks/rabobank.rb b/lib/mt940/banks/rabobank.rb index 9a05b8e..f1d4d4f 100644 --- a/lib/mt940/banks/rabobank.rb +++ b/lib/mt940/banks/rabobank.rb @@ -15,14 +15,4 @@ def parse_tag_61 end end - def parse_tag_86 - if @line.match(/^:86:(.*)$/) - if @transaction.description.nil? - @transaction.description= $1.strip - else - @transaction.description += ' ' +$1.strip - end - end - end - end diff --git a/lib/mt940/banks/triodos.rb b/lib/mt940/banks/triodos.rb index 6bfdb96..ee89533 100644 --- a/lib/mt940/banks/triodos.rb +++ b/lib/mt940/banks/triodos.rb @@ -5,9 +5,9 @@ def self.determine_bank(*args) end def parse_contra_account - if @transaction && @transaction.description.match(/\d+(\d{9})$/) + if @transaction && @transaction.contra_account.nil? && @transaction.description.match(/000\d+(\d{9})(.*)/) && @transaction.contra_account = $1.rjust(9, '000000000') - @transaction.description = '' + @transaction.description = $2.strip end end diff --git a/lib/mt940/base.rb b/lib/mt940/base.rb index 452bb5b..ef887dc 100644 --- a/lib/mt940/base.rb +++ b/lib/mt940/base.rb @@ -1,6 +1,5 @@ #encoding: utf-8 module MT940 - class Base attr_accessor :bank @@ -52,14 +51,12 @@ def initialize(file) def parse_tag(tag) @tag86 = false if tag.to_s != '86' send("parse_tag_#{tag}") - parse_contra_account if @transaction && @transaction.description end def parse_tag_25 @line.gsub!('.','') if @line.match(/^:\d{2}:[^\d]*(\d*)/) @bank_account = $1.gsub(/^0/,'') - @tag86 = false end end @@ -73,21 +70,28 @@ def parse_tag_61 @transaction = MT940::Transaction.new(:bank_account => @bank_account, :amount => type * ($3 + '.' + $4).to_f, :bank => @bank, :currency => @currency) @transaction.date = parse_date($1) @transactions << @transaction - @tag86 = false end end def parse_tag_86 - if !@transaction.description && @line.match(/^:86:\s?(.*)$/) + if @line.match(/^:86:\s?(.*)$/) && parse_tag_86? @tag86 = true - @transaction.description = $1.gsub(/>\d{2}/,'').strip + @transaction.description ||= '' + @transaction.description += (@transaction.description == '' ? '' : ' ') + $1.gsub(/>\d{2}/,'') + @transaction.description.strip! + parse_contra_account end end + def parse_tag_86? + true + end + def parse_line - if @tag86 && @transaction.description + if @tag86 @transaction.description += ' ' + @line.gsub(/\n/,'').gsub(/>\d{2}\s*/,'').gsub(/\-XXX/,'').gsub(/-$/,'').strip @transaction.description.strip! + parse_contra_account end end @@ -101,6 +105,6 @@ def parse_contra_account #Fail silently def method_missing(*args) end - end -end + end +end \ No newline at end of file diff --git a/lib/mt940/transaction.rb b/lib/mt940/transaction.rb index 8c33e7f..0219e90 100644 --- a/lib/mt940/transaction.rb +++ b/lib/mt940/transaction.rb @@ -1,5 +1,4 @@ module MT940 - class Transaction attr_accessor :bank_account, :contra_account, :amount, :description, :contra_account_owner, :date, :bank, :currency @@ -16,5 +15,4 @@ def initialize(attributes = {}) end end - end \ No newline at end of file From 76db2db67439dc8a30133eb6defffee0ae6bc0c3 Mon Sep 17 00:00:00 2001 From: Roma Druzhinin Date: Mon, 17 Dec 2012 15:37:02 +0400 Subject: [PATCH 07/10] Added support of statements with transactions --- README.md | 5 ++++ lib/mt940.rb | 6 ++-- lib/mt940/banks/abnamro.rb | 3 +- lib/mt940/banks/rabobank.rb | 1 + lib/mt940/base.rb | 60 ++++++++++++++++++++++++++++++++++--- lib/mt940/statement.rb | 25 ++++++++++++++++ test/fixtures/abnamro.txt | 4 +-- test/fixtures/ing.txt | 2 +- test/fixtures/rabobank.txt | 2 +- test/fixtures/triodos.txt | 2 +- test/mt940_abnamro_test.rb | 53 +++++++++++++++++++++++++++++++- test/mt940_base_test.rb | 46 ++++++++++++++++++++++++++-- test/mt940_ing_test.rb | 50 +++++++++++++++++++++++++++++++ test/mt940_rabobank_test.rb | 49 ++++++++++++++++++++++++++++++ test/mt940_triodos_test.rb | 50 +++++++++++++++++++++++++++++++ 15 files changed, 343 insertions(+), 15 deletions(-) create mode 100644 lib/mt940/statement.rb diff --git a/README.md b/README.md index db829ad..8f10564 100644 --- a/README.md +++ b/README.md @@ -22,6 +22,8 @@ With the file name as argument: file_name = '/Users/dovadi/Downloads/ing.940' @transactions = MT940::Base.transactions(file_name) + or + @statements = MT940::Base.statements(file_name) or with the file itself: @@ -30,6 +32,8 @@ or with the file itself: file = File.open(file_name) @transactions = MT940::Base.transactions(file) + or + @statements = MT940::Base.statements(file) * Independent of the bank, a transaction always consists of: @@ -42,6 +46,7 @@ or with the file itself: - contra account * With the Rabobank its owner is extracted as well. +* Statement number and sequence doesn`t work for Ing, Triodos Running tests ============= diff --git a/lib/mt940.rb b/lib/mt940.rb index 461e40b..5842918 100644 --- a/lib/mt940.rb +++ b/lib/mt940.rb @@ -1,11 +1,13 @@ $:.unshift(File.dirname(__FILE__)) unless $:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__))) +require 'bigdecimal' require 'tempfile' require 'mt940/base' +require 'mt940/statement' require 'mt940/transaction' require 'mt940/banks/ing' -require 'mt940/banks/rabobank' require 'mt940/banks/abnamro' +require 'mt940/banks/deutsche_bank' require 'mt940/banks/triodos' -require 'mt940/banks/deutsche_bank' \ No newline at end of file +require 'mt940/banks/rabobank' \ No newline at end of file diff --git a/lib/mt940/banks/abnamro.rb b/lib/mt940/banks/abnamro.rb index 737b117..85ea189 100644 --- a/lib/mt940/banks/abnamro.rb +++ b/lib/mt940/banks/abnamro.rb @@ -7,8 +7,9 @@ def self.determine_bank(*args) def parse_tag_61 if @line.match(/^:61:(\d{6})\d{4}(C|D)(\d+),(\d{0,2})/) type = $2 == 'D' ? -1 : 1 - @transaction = MT940::Transaction.new(:bank_account => @bank_account, :amount => type * ($3 + '.' + $4).to_f, :bank => @bank, :currency => @currency) + @transaction = MT940::Transaction.new(bank_account: @bank_account, amount: type * BigDecimal.new($3 + '.' + $4), bank: @bank, currency: @currency) @transaction.date = parse_date($1) + @statement_transactions << @transaction @transactions << @transaction @tag86 = false end diff --git a/lib/mt940/banks/rabobank.rb b/lib/mt940/banks/rabobank.rb index f1d4d4f..eb7502f 100644 --- a/lib/mt940/banks/rabobank.rb +++ b/lib/mt940/banks/rabobank.rb @@ -11,6 +11,7 @@ def parse_tag_61 @transaction.date = parse_date($1) @transaction.contra_account = $5.strip @transaction.contra_account_owner = $6.strip + @statement_transactions << @transaction @transactions << @transaction end end diff --git a/lib/mt940/base.rb b/lib/mt940/base.rb index ef887dc..2e2914f 100644 --- a/lib/mt940/base.rb +++ b/lib/mt940/base.rb @@ -5,6 +5,15 @@ class Base attr_accessor :bank def self.transactions(file) + process(file, :transactions) + end + + def self.statements(file) + process(file, :statements) + end + + + def self.process(file, type) file = File.open(file, 'r:utf-8') if file.is_a?(String) if file.is_a?(File) || file.is_a?(Tempfile) first_line = file.readline @@ -13,18 +22,20 @@ def self.transactions(file) file.rewind instance = klass.new(file) file.close - instance.parse + instance.parse(type) else raise ArgumentError.new('No file is given!') end + end - def parse + def parse(type = :transactions) @tag86 = false @lines.each do |line| @line = line @line.match(/^:(\d{2}F?):/) ? parse_tag($1) : parse_line end + return @statements if type == :statements @transactions end @@ -43,6 +54,8 @@ def self.determine_bank(*args) def initialize(file) @transactions = [] + @statements = [] + @statement_transactions = [] @bank = self.class.to_s.split('::').last @bank = 'Unknown' if @bank == 'Base' @lines = file.readlines @@ -60,19 +73,58 @@ def parse_tag_25 end end + def parse_tag_28 + if @line.match(/^:28:(\d{1,5})\/(\d{1,3})/) + @number, @sequence = $1.to_i, $2.to_i + end + end + def parse_tag_60F - @currency = @line[12..14] + if @line.match(/^:60F:(C|D)(\d{6})([A-Z]{3})(\d{1,15}),(\d{0,2})/) + type = $1 == 'D' ? -1 : 1 + @opening_balance_amount = type * BigDecimal.new("#{$4}.#{$5}") + @opening_balance_currency = $3 + @opening_balance_date = parse_date($2) + @currency = @line[12..14] + end end def parse_tag_61 if @line.match(/^:61:(\d{6})(C|D)(\d+),(\d{0,2})/) type = $2 == 'D' ? -1 : 1 - @transaction = MT940::Transaction.new(:bank_account => @bank_account, :amount => type * ($3 + '.' + $4).to_f, :bank => @bank, :currency => @currency) + @transaction = MT940::Transaction.new(:bank_account => @bank_account, :amount => type * BigDecimal.new($3 + '.' + $4), :bank => @bank, :currency => @currency) @transaction.date = parse_date($1) + @statement_transactions << @transaction @transactions << @transaction end end + def parse_tag_62F + if @line.match(/^:62F:(C|D)(\d{6})([A-Z]{3})(\d{1,15}),(\d{0,2})/) + type = $1 == 'D' ? -1 : 1 + @closing_balance_date = parse_date($2) + @closing_balance_currency = $3 + @closing_balance_amount = type * BigDecimal.new("#{$4}.#{$5}") + amount_valid = (@opening_balance_amount + @statement_transactions.inject(0){|memo, transaction| memo + transaction.amount}) == @closing_balance_amount + @statements << MT940::Statement.new( + number: @number, + sequence: @sequence, + bank: @bank, + bank_account: @bank_account, + opening_balance_amount: @opening_balance_amount, + opening_balance_currency: @opening_balance_currency, + opening_balance_date: @opening_balance_date, + closing_balance_amount: @closing_balance_amount, + closing_balance_currency: @closing_balance_currency, + closing_balance_date: @closing_balance_date, + amount_valid: amount_valid, + transactions: @statement_transactions + ) + @statement_transactions = [] + end + end + + def parse_tag_86 if @line.match(/^:86:\s?(.*)$/) && parse_tag_86? @tag86 = true diff --git a/lib/mt940/statement.rb b/lib/mt940/statement.rb new file mode 100644 index 0000000..dba3a0a --- /dev/null +++ b/lib/mt940/statement.rb @@ -0,0 +1,25 @@ +module MT940 + class Statement + + attr_accessor :number, :sequence, :bank, :bank_account, :opening_balance_amount, + :opening_balance_currency, :opening_balance_date, :plain, :closing_balance_amount, + :closing_balance_currency, :closing_balance_date, :transactions, :amount_valid + + def initialize(attributes = {}) + @number = attributes[:number] + @sequence = attributes[:sequence] + @bank = attributes[:bank] + @bank_account = attributes[:bank_account] + @opening_balance_amount = attributes[:opening_balance_amount] + @opening_balance_currency = attributes[:opening_balance_currency] + @opening_balance_date = attributes[:opening_balance_date] + @closing_balance_amount = attributes[:closing_balance_amount] + @closing_balance_currency = attributes[:closing_balance_currency] + @closing_balance_date = attributes[:closing_balance_date] + @plain = attributes[:plain] + @amount_valid = attributes[:amount_valid] + @transactions = attributes[:transactions] + end + + end +end \ No newline at end of file diff --git a/test/fixtures/abnamro.txt b/test/fixtures/abnamro.txt index 9e18d89..d680cf4 100644 --- a/test/fixtures/abnamro.txt +++ b/test/fixtures/abnamro.txt @@ -24,7 +24,7 @@ INCL. 1,44 BTW :86:BEA NR:XXX1234 21.05.11/12.04 HANS ANDERS OPT./056 KAT,PAS999 :61:1105220523D141,48N426NONREF :86:BEA NR:XXX1234 22.05.11/13.45 MYCOM DEN HAAG S-GRAVEN,PAS999 -:62F:C110523EUR876,84 +:62F:C110523EUR2914,84 - ABNANL2A 940 @@ -32,7 +32,7 @@ ABNANL2A :20:ABN AMRO BANK NV :25:517852257 :28:19322/1 -:60F:C110523EUR2876,84 +:60F:C110523EUR2914,84 :61:1105240524D9,49N426NONREF :86:BEA NR:XXX1234 24.05.11/09.18 PETS PLACE KATWIJK KATWI,PAS999 :61:1105240524D15,N426NONREF diff --git a/test/fixtures/ing.txt b/test/fixtures/ing.txt index 09220de..9d718f1 100644 --- a/test/fixtures/ing.txt +++ b/test/fixtures/ing.txt @@ -19,6 +19,6 @@ ING Bank N.V. tarifering ING :86:0111111111 GPPeking 170000001AC :61:100722C3,68NVZ NONREF :86:0123456789 EJ46GREENP100610T1456 CLIEOP TMG GPHONGKONG AMSTERDAM -:62F:C100723EUR3,47 +:62F:D100723EUR46,59 :86:D000004C000002D25,24C28,71 -XXX \ No newline at end of file diff --git a/test/fixtures/rabobank.txt b/test/fixtures/rabobank.txt index ff6faf7..d911b6b 100644 --- a/test/fixtures/rabobank.txt +++ b/test/fixtures/rabobank.txt @@ -8,7 +8,7 @@ :86:NIET AKKOORD MET AFSCHRIJVING :86:KOSTEN KINDEROPVANG JUNI :86:20095731 -:62F:C110615EUR000000000395,82 +:62F:D110615EUR000000000740,11 :20:940A110616 :25:1291.99.348EUR diff --git a/test/fixtures/triodos.txt b/test/fixtures/triodos.txt index ccb57c0..2e50877 100644 --- a/test/fixtures/triodos.txt +++ b/test/fixtures/triodos.txt @@ -9,6 +9,6 @@ :61:110125D700,00N000NONREF :86:000>100133967858 >20 HUUR>21 KANTOOR - FEB 2010 -:62F:C110201EUR4370,79 +:62F:C110201EUR4259,39 - diff --git a/test/mt940_abnamro_test.rb b/test/mt940_abnamro_test.rb index b42aedf..a8b5392 100644 --- a/test/mt940_abnamro_test.rb +++ b/test/mt940_abnamro_test.rb @@ -6,12 +6,19 @@ def setup file_name = File.dirname(__FILE__) + '/fixtures/abnamro.txt' @transactions = MT940::Base.transactions(file_name) @transaction = @transactions.first + @statements = MT940::Base.statements(file_name) + @statement = @statements.first end - + should 'have the correct number of transactions' do assert_equal 10, @transactions.size end + should 'have the correct number of statements' do + assert_equal 2, @statements.size + end + + context 'Transaction' do should 'have a bank_account' do assert_equal '517852257', @transaction.bank_account @@ -54,4 +61,48 @@ def setup end end + + context 'Statements' do + should 'have a number' do + assert_equal 19321, @statement.number + end + + should 'have a sequence' do + assert_equal 1, @statement.sequence + end + + should 'have a bank_account' do + assert_equal '517852257', @statement.bank_account + end + + should 'have an opening_balance_amount' do + assert_equal 3236.28, @statement.opening_balance_amount + end + + should 'have an opening_balance_date' do + assert_equal Date.new(2011,5,22), @statement.opening_balance_date + end + + should 'have an opening_balance_currency' do + assert_equal 'EUR', @statement.opening_balance_currency + end + + should 'have an closing_balance_amount' do + assert_equal 2914.84, @statement.closing_balance_amount + end + + should 'have an closing_balance_date' do + assert_equal Date.new(2011,5,23), @statement.closing_balance_date + end + + should 'have an closing_balance_currency' do + assert_equal 'EUR', @statement.closing_balance_currency + end + + should 'have valid amount' do + assert_equal true, @statement.amount_valid + end + end + + end diff --git a/test/mt940_base_test.rb b/test/mt940_base_test.rb index 6fffb45..ee26dc0 100644 --- a/test/mt940_base_test.rb +++ b/test/mt940_base_test.rb @@ -9,6 +9,12 @@ class TestMt940Base < Test::Unit::TestCase assert_equal 6, @transactions.size end + should 'read the statements with the filename of the MT940 file' do + file_name = File.dirname(__FILE__) + '/fixtures/ing.txt' + @statements = MT940::Base.statements(file_name) + assert_equal 1, @statements.size + end + should 'read the transactions with the handle to the mt940 file itself' do file_name = File.dirname(__FILE__) + '/fixtures/ing.txt' file = File.open(file_name, 'r:utf-8') @@ -16,6 +22,14 @@ class TestMt940Base < Test::Unit::TestCase assert_equal 6, @transactions.size end + should 'read the statements with the handle to the mt940 file itself' do + file_name = File.dirname(__FILE__) + '/fixtures/ing.txt' + file = File.open(file_name, 'r:utf-8') + @statements = MT940::Base.statements(file) + assert_equal 1, @statements.size + end + + #Tempfile is used by Paperclip, so the following will work: #MT940::Base.transactions(@mt940_file.attachment.to_file) should 'read the transactions with the handle of a Tempfile' do @@ -27,26 +41,54 @@ class TestMt940Base < Test::Unit::TestCase file.unlink end - should 'raise an exception if the file does not exist' do + should 'read the statements with the handle of a Tempfile' do + file = Tempfile.new('temp') + file.write(':940:') + file.rewind + @statements = MT940::Base.statements(file) + assert_equal 0, @statements.size + file.unlink + end + + + should '@transaction raise an exception if the file does not exist' do file_name = File.dirname(__FILE__) + '/fixtures/123.txt' assert_raise Errno::ENOENT do @transactions = MT940::Base.transactions(file_name) end end + should 'statement raise an exception if the file does not exist' do + file_name = File.dirname(__FILE__) + '/fixtures/123.txt' + assert_raise Errno::ENOENT do + @transactions = MT940::Base.statements(file_name) + end + end + + should 'raise an ArgumentError if a wrong argument was given' do assert_raise ArgumentError do MT940::Base.transactions(Hash.new) end end + + end context 'Unknown MT940 file' do - should 'return its bank' do + should 'transaction return its bank' do file_name = File.dirname(__FILE__) + '/fixtures/unknown.txt' @transactions = MT940::Base.transactions(file_name) assert_equal 'Unknown', @transactions.first.bank end + + should 'statement return its bank' do + file_name = File.dirname(__FILE__) + '/fixtures/unknown.txt' + @statements = MT940::Base.statements(file_name) + assert_equal 'Unknown', @statements.first.bank + end + end + end diff --git a/test/mt940_ing_test.rb b/test/mt940_ing_test.rb index 1a32d09..3b7748a 100644 --- a/test/mt940_ing_test.rb +++ b/test/mt940_ing_test.rb @@ -6,12 +6,19 @@ def setup file_name = File.dirname(__FILE__) + '/fixtures/ing.txt' @transactions = MT940::Base.transactions(file_name) @transaction = @transactions.first + @statements = MT940::Base.statements(file_name) + @statement = @statements.first end should 'have the correct number of transactions' do assert_equal 6, @transactions.size end + should 'have the correct number of statements' do + assert_equal 1, @statements.size + end + + context 'Transaction' do should 'have a bank_account' do assert_equal '001234567', @transaction.bank_account @@ -43,4 +50,47 @@ def setup end + context 'Statements' do + #should 'have a number' do + # assert_equal 19321, @statement.number + #end + + #should 'have a sequence' do + # assert_equal 1, @statement.sequence + #end + + should 'have a bank_account' do + assert_equal '001234567', @statement.bank_account + end + + should 'have an opening_balance_amount' do + assert_equal 0.0, @statement.opening_balance_amount + end + + should 'have an opening_balance_date' do + assert_equal Date.new(2010,7,22), @statement.opening_balance_date + end + + should 'have an opening_balance_currency' do + assert_equal 'EUR', @statement.opening_balance_currency + end + + should 'have an closing_balance_amount' do + assert_equal -46.59, @statement.closing_balance_amount + end + + should 'have an closing_balance_date' do + assert_equal Date.new(2010,7,23), @statement.closing_balance_date + end + + should 'have an closing_balance_currency' do + assert_equal 'EUR', @statement.closing_balance_currency + end + + should 'have valid amount' do + assert_equal true, @statement.amount_valid + end + end + + end diff --git a/test/mt940_rabobank_test.rb b/test/mt940_rabobank_test.rb index 3cdd5c7..dc01103 100644 --- a/test/mt940_rabobank_test.rb +++ b/test/mt940_rabobank_test.rb @@ -6,12 +6,19 @@ def setup file_name = File.dirname(__FILE__) + '/fixtures/rabobank.txt' @transactions = MT940::Base.transactions(file_name) @transaction = @transactions.first + @statements = MT940::Base.statements(file_name) + @statement = @statements.first end should 'have the correct number of transactions' do assert_equal 3, @transactions.size end + should 'have the correct number of statements' do + assert_equal 3, @statements.size + end + + context 'Transaction' do should 'have a bank_account' do assert_equal '129199348', @transaction.bank_account @@ -57,4 +64,46 @@ def setup end + context 'Statements' do + should 'have a number' do + assert_equal 0, @statement.number + end + + should 'have a sequence' do + assert_equal 0, @statement.sequence + end + + should 'have a bank_account' do + assert_equal '129199348', @statement.bank_account + end + + should 'have an opening_balance_amount' do + assert_equal 473.17, @statement.opening_balance_amount + end + + should 'have an opening_balance_date' do + assert_equal Date.new(2011, 6, 14), @statement.opening_balance_date + end + + should 'have an opening_balance_currency' do + assert_equal 'EUR', @statement.opening_balance_currency + end + + should 'have an closing_balance_amount' do + assert_equal -740.11, @statement.closing_balance_amount + end + + should 'have an closing_balance_date' do + assert_equal Date.new(2011, 6, 15), @statement.closing_balance_date + end + + should 'have an closing_balance_currency' do + assert_equal 'EUR', @statement.closing_balance_currency + end + + should 'have valid amount' do + assert_equal true, @statement.amount_valid + end + end + end diff --git a/test/mt940_triodos_test.rb b/test/mt940_triodos_test.rb index 3b06677..504e88e 100644 --- a/test/mt940_triodos_test.rb +++ b/test/mt940_triodos_test.rb @@ -6,12 +6,19 @@ def setup file_name = File.dirname(__FILE__) + '/fixtures/triodos.txt' @transactions = MT940::Base.transactions(file_name) @transaction = @transactions.first + @statements = MT940::Base.statements(file_name) + @statement = @statements.first end should 'have the correct number of transactions' do assert_equal 2, @transactions.size end + should 'have the correct number of statements' do + assert_equal 1, @statements.size + end + + context 'Transaction' do should 'have a bank_account' do assert_equal '390123456', @transaction.bank_account @@ -43,4 +50,47 @@ def setup end + context 'Statements' do + #should 'have a number' do + # assert_equal 19321, @statement.number + #end + # + #should 'have a sequence' do + # assert_equal 1, @statement.sequence + #end + + should 'have a bank_account' do + assert_equal '390123456', @statement.bank_account + end + + should 'have an opening_balance_amount' do + assert_equal 4975.09, @statement.opening_balance_amount + end + + should 'have an opening_balance_date' do + assert_equal Date.new(2011,1,1), @statement.opening_balance_date + end + + should 'have an opening_balance_currency' do + assert_equal 'EUR', @statement.opening_balance_currency + end + + should 'have an closing_balance_amount' do + assert_equal 4259.39, @statement.closing_balance_amount + end + + should 'have an closing_balance_date' do + assert_equal Date.new(2011,2,1), @statement.closing_balance_date + end + + should 'have an closing_balance_currency' do + assert_equal 'EUR', @statement.closing_balance_currency + end + + should 'have valid amount' do + assert_equal true, @statement.amount_valid + end + end + + end From 9516e21f88dafaf695354ae4a2a4d01c6a0fc6cd Mon Sep 17 00:00:00 2001 From: Roma Druzhinin Date: Mon, 17 Dec 2012 22:29:32 +0400 Subject: [PATCH 08/10] Reverted to old style hashes to make gem work on 1.8.7 and make all test passes --- lib/mt940/banks/abnamro.rb | 2 +- lib/mt940/banks/rabobank.rb | 2 +- lib/mt940/base.rb | 64 ++++++++++++++++++------------------- 3 files changed, 34 insertions(+), 34 deletions(-) diff --git a/lib/mt940/banks/abnamro.rb b/lib/mt940/banks/abnamro.rb index 85ea189..04a8b6f 100644 --- a/lib/mt940/banks/abnamro.rb +++ b/lib/mt940/banks/abnamro.rb @@ -7,7 +7,7 @@ def self.determine_bank(*args) def parse_tag_61 if @line.match(/^:61:(\d{6})\d{4}(C|D)(\d+),(\d{0,2})/) type = $2 == 'D' ? -1 : 1 - @transaction = MT940::Transaction.new(bank_account: @bank_account, amount: type * BigDecimal.new($3 + '.' + $4), bank: @bank, currency: @currency) + @transaction = MT940::Transaction.new(:bank_account => @bank_account, :amount => type * BigDecimal.new($3 + '.' + $4), :bank => @bank, :currency => @currency) @transaction.date = parse_date($1) @statement_transactions << @transaction @transactions << @transaction diff --git a/lib/mt940/banks/rabobank.rb b/lib/mt940/banks/rabobank.rb index eb7502f..557e0eb 100644 --- a/lib/mt940/banks/rabobank.rb +++ b/lib/mt940/banks/rabobank.rb @@ -7,7 +7,7 @@ def self.determine_bank(*args) def parse_tag_61 if @line.match(/^:61:(\d{6})(C|D)(\d+),(\d{0,2})\w{4}\w{1}(\d{9}|NONREF)(.+)$/) type = $2 == 'D' ? -1 : 1 - @transaction = MT940::Transaction.new(:bank_account => @bank_account, :amount => type * ($3 + '.' + $4).to_f, :bank => @bank, :currency => @currency) + @transaction = MT940::Transaction.new(:bank_account => @bank_account, :amount => type * BigDecimal.new($3 + '.' + $4), :bank => @bank, :currency => @currency) @transaction.date = parse_date($1) @transaction.contra_account = $5.strip @transaction.contra_account_owner = $6.strip diff --git a/lib/mt940/base.rb b/lib/mt940/base.rb index 2e2914f..cc77402 100644 --- a/lib/mt940/base.rb +++ b/lib/mt940/base.rb @@ -14,11 +14,11 @@ def self.statements(file) def self.process(file, type) - file = File.open(file, 'r:utf-8') if file.is_a?(String) + file = File.open(file, 'r:utf-8') if file.is_a?(String) if file.is_a?(File) || file.is_a?(Tempfile) - first_line = file.readline + first_line = file.readline second_line = file.readline unless file.eof? - klass = determine_bank(first_line, second_line) + klass = determine_bank(first_line, second_line) file.rewind instance = klass.new(file) file.close @@ -44,7 +44,7 @@ def parse(type = :transactions) def self.determine_bank(*args) Dir.foreach(File.dirname(__FILE__) + '/banks/') do |file| if file.match(/\.rb$/) - klass = eval(file.gsub(/\.rb$/,'').split('_').map{|e| e.capitalize}.join) + klass = eval(file.gsub(/\.rb$/, '').split('_').map { |e| e.capitalize }.join) bank = klass.determine_bank(*args) return bank if bank end @@ -53,11 +53,11 @@ def self.determine_bank(*args) end def initialize(file) - @transactions = [] - @statements = [] + @transactions = [] + @statements = [] @statement_transactions = [] - @bank = self.class.to_s.split('::').last - @bank = 'Unknown' if @bank == 'Base' + @bank = self.class.to_s.split('::').last + @bank = 'Unknown' if @bank == 'Base' @lines = file.readlines end @@ -67,9 +67,9 @@ def parse_tag(tag) end def parse_tag_25 - @line.gsub!('.','') + @line.gsub!('.', '') if @line.match(/^:\d{2}:[^\d]*(\d*)/) - @bank_account = $1.gsub(/^0/,'') + @bank_account = $1.gsub(/^0/, '') end end @@ -81,18 +81,18 @@ def parse_tag_28 def parse_tag_60F if @line.match(/^:60F:(C|D)(\d{6})([A-Z]{3})(\d{1,15}),(\d{0,2})/) - type = $1 == 'D' ? -1 : 1 - @opening_balance_amount = type * BigDecimal.new("#{$4}.#{$5}") + type = $1 == 'D' ? -1 : 1 + @opening_balance_amount = type * BigDecimal.new("#{$4}.#{$5}") @opening_balance_currency = $3 - @opening_balance_date = parse_date($2) - @currency = @line[12..14] + @opening_balance_date = parse_date($2) + @currency = @line[12..14] end end def parse_tag_61 if @line.match(/^:61:(\d{6})(C|D)(\d+),(\d{0,2})/) - type = $2 == 'D' ? -1 : 1 - @transaction = MT940::Transaction.new(:bank_account => @bank_account, :amount => type * BigDecimal.new($3 + '.' + $4), :bank => @bank, :currency => @currency) + type = $2 == 'D' ? -1 : 1 + @transaction = MT940::Transaction.new(:bank_account => @bank_account, :amount => type * BigDecimal.new($3 + '.' + $4), :bank => @bank, :currency => @currency) @transaction.date = parse_date($1) @statement_transactions << @transaction @transactions << @transaction @@ -105,20 +105,20 @@ def parse_tag_62F @closing_balance_date = parse_date($2) @closing_balance_currency = $3 @closing_balance_amount = type * BigDecimal.new("#{$4}.#{$5}") - amount_valid = (@opening_balance_amount + @statement_transactions.inject(0){|memo, transaction| memo + transaction.amount}) == @closing_balance_amount + amount_valid = (@opening_balance_amount + @statement_transactions.inject(0) { |memo, transaction| memo + transaction.amount }) == @closing_balance_amount @statements << MT940::Statement.new( - number: @number, - sequence: @sequence, - bank: @bank, - bank_account: @bank_account, - opening_balance_amount: @opening_balance_amount, - opening_balance_currency: @opening_balance_currency, - opening_balance_date: @opening_balance_date, - closing_balance_amount: @closing_balance_amount, - closing_balance_currency: @closing_balance_currency, - closing_balance_date: @closing_balance_date, - amount_valid: amount_valid, - transactions: @statement_transactions + :number => @number, + :sequence => @sequence, + :bank => @bank, + :bank_account => @bank_account, + :opening_balance_amount => @opening_balance_amount, + :opening_balance_currency => @opening_balance_currency, + :opening_balance_date => @opening_balance_date, + :closing_balance_amount => @closing_balance_amount, + :closing_balance_currency => @closing_balance_currency, + :closing_balance_date => @closing_balance_date, + :amount_valid => amount_valid, + :transactions => @statement_transactions ) @statement_transactions = [] end @@ -127,9 +127,9 @@ def parse_tag_62F def parse_tag_86 if @line.match(/^:86:\s?(.*)$/) && parse_tag_86? - @tag86 = true + @tag86 = true @transaction.description ||= '' - @transaction.description += (@transaction.description == '' ? '' : ' ') + $1.gsub(/>\d{2}/,'') + @transaction.description += (@transaction.description == '' ? '' : ' ') + $1.gsub(/>\d{2}/, '') @transaction.description.strip! parse_contra_account end @@ -141,7 +141,7 @@ def parse_tag_86? def parse_line if @tag86 - @transaction.description += ' ' + @line.gsub(/\n/,'').gsub(/>\d{2}\s*/,'').gsub(/\-XXX/,'').gsub(/-$/,'').strip + @transaction.description += ' ' + @line.gsub(/\n/, '').gsub(/>\d{2}\s*/, '').gsub(/\-XXX/, '').gsub(/-$/, '').strip @transaction.description.strip! parse_contra_account end From 4b95a47cef8c619b4d1ceda5a1bd9c989be2095a Mon Sep 17 00:00:00 2001 From: Roma Druzhinin Date: Tue, 18 Dec 2012 10:30:04 +0400 Subject: [PATCH 09/10] Removed Deutsche Bank untill tests for it. --- lib/mt940/banks/deutsche_bank.rb | 16 ---------------- 1 file changed, 16 deletions(-) delete mode 100644 lib/mt940/banks/deutsche_bank.rb diff --git a/lib/mt940/banks/deutsche_bank.rb b/lib/mt940/banks/deutsche_bank.rb deleted file mode 100644 index ef66b4e..0000000 --- a/lib/mt940/banks/deutsche_bank.rb +++ /dev/null @@ -1,16 +0,0 @@ -class MT940::DeutscheBank < MT940::Abnamro - - def self.determine_bank(*args) - self if args[0].match(/DEUTDE/) - end - - def parse_contra_account - if @transaction - if @transaction.description.match(/(.+)\/\/ACCW\/(\d+)\//) - @transaction.contra_account = $2 - @transaction.description = $1.strip - end - end - end - -end From a9dbb9deb4e9c0f45a724cee0717506b6ae5ba9b Mon Sep 17 00:00:00 2001 From: Roma Druzhinin Date: Tue, 18 Dec 2012 10:30:04 +0400 Subject: [PATCH 10/10] Removed Deutsche Bank untill tests for it. --- lib/mt940.rb | 1 - lib/mt940/banks/deutsche_bank.rb | 16 ---------------- 2 files changed, 17 deletions(-) delete mode 100644 lib/mt940/banks/deutsche_bank.rb diff --git a/lib/mt940.rb b/lib/mt940.rb index 5842918..8625c63 100644 --- a/lib/mt940.rb +++ b/lib/mt940.rb @@ -8,6 +8,5 @@ require 'mt940/transaction' require 'mt940/banks/ing' require 'mt940/banks/abnamro' -require 'mt940/banks/deutsche_bank' require 'mt940/banks/triodos' require 'mt940/banks/rabobank' \ No newline at end of file diff --git a/lib/mt940/banks/deutsche_bank.rb b/lib/mt940/banks/deutsche_bank.rb deleted file mode 100644 index ef66b4e..0000000 --- a/lib/mt940/banks/deutsche_bank.rb +++ /dev/null @@ -1,16 +0,0 @@ -class MT940::DeutscheBank < MT940::Abnamro - - def self.determine_bank(*args) - self if args[0].match(/DEUTDE/) - end - - def parse_contra_account - if @transaction - if @transaction.description.match(/(.+)\/\/ACCW\/(\d+)\//) - @transaction.contra_account = $2 - @transaction.description = $1.strip - end - end - end - -end