Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Gemfile
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
source "http://rubygems.org"

gem 'rake', '0.8.7'
gem 'rake'

gemspec
18 changes: 14 additions & 4 deletions Gemfile.lock
Original file line number Diff line number Diff line change
@@ -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
5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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:

Expand All @@ -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:
Expand All @@ -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
=============
Expand Down
6 changes: 4 additions & 2 deletions lib/mt940.rb
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
$:.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/triodos'
require 'mt940/banks/triodos'
require 'mt940/banks/rabobank'
7 changes: 4 additions & 3 deletions lib/mt940/banks/abnamro.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -18,9 +19,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
Expand Down
5 changes: 4 additions & 1 deletion lib/mt940/banks/ing.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,11 @@ 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

def parse_tag_86?
@transaction.description.nil?
end
end
13 changes: 2 additions & 11 deletions lib/mt940/banks/rabobank.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,22 +7,13 @@ 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
@statement_transactions << @transaction
@transactions << @transaction
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
4 changes: 2 additions & 2 deletions lib/mt940/banks/triodos.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
112 changes: 86 additions & 26 deletions lib/mt940/base.rb
Original file line number Diff line number Diff line change
@@ -1,30 +1,41 @@
#encoding: utf-8
module MT940

class Base

attr_accessor :bank

def self.transactions(file)
file = File.open(file) if file.is_a?(String)
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
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
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?):/) ? eval('parse_tag_'+ $1) : parse_line
@line.match(/^:(\d{2}F?):/) ? parse_tag($1) : parse_line
end
return @statements if type == :statements
@transactions
end

Expand All @@ -33,7 +44,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
Expand All @@ -42,47 +53,97 @@ def self.determine_bank(*args)
end

def initialize(file)
@transactions = []
@bank = self.class.to_s.split('::').last
@bank = 'Unknown' if @bank == 'Base'
@transactions = []
@statements = []
@statement_transactions = []
@bank = self.class.to_s.split('::').last
@bank = 'Unknown' if @bank == 'Base'
@lines = file.readlines
end

def parse_tag(tag)
@tag86 = false if tag.to_s != '86'
send("parse_tag_#{tag}")
end

def parse_tag_25
@line.gsub!('.','')
@line.gsub!('.', '')
if @line.match(/^:\d{2}:[^\d]*(\d*)/)
@bank_account = $1.gsub(/^0/,'')
@tag86 = false
@bank_account = $1.gsub(/^0/, '')
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)
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
@tag86 = false
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 !@tag86 && @line.match(/^:86:\s?(.*)$/)
@tag86 = true
@transaction.description = $1.gsub(/>\d{2}/,'').strip
if @line.match(/^:86:\s?(.*)$/) && parse_tag_86?
@tag86 = true
@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
@transaction.description.lstrip!
@transaction.description += ' ' + @line.gsub(/\n/,'').gsub(/>\d{2}\s*/,'').gsub(/\-XXX/,'').gsub(/-$/,'').strip
if @tag86
@transaction.description += ' ' + @line.gsub(/\n/, '').gsub(/>\d{2}\s*/, '').gsub(/\-XXX/, '').gsub(/-$/, '').strip
@transaction.description.strip!
parse_contra_account
end
end

Expand All @@ -98,5 +159,4 @@ def method_missing(*args)
end

end

end
end
25 changes: 25 additions & 0 deletions lib/mt940/statement.rb
Original file line number Diff line number Diff line change
@@ -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
2 changes: 0 additions & 2 deletions lib/mt940/transaction.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
module MT940

class Transaction

attr_accessor :bank_account, :contra_account, :amount, :description, :contra_account_owner, :date, :bank, :currency
Expand All @@ -16,5 +15,4 @@ def initialize(attributes = {})
end

end

end
4 changes: 2 additions & 2 deletions test/fixtures/abnamro.txt
Original file line number Diff line number Diff line change
Expand Up @@ -24,15 +24,15 @@ 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
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
Expand Down
Loading