volksbanker 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +4 -0
- data/Gemfile +4 -0
- data/README.md +23 -0
- data/Rakefile +9 -0
- data/bin/vb +9 -0
- data/lib/volksbanker/amex_line_item.rb +19 -0
- data/lib/volksbanker/cli.rb +19 -0
- data/lib/volksbanker/version.rb +3 -0
- data/lib/volksbanker/volksbank_file_reader.rb +62 -0
- data/lib/volksbanker/volksbank_line_item.rb +46 -0
- data/lib/volksbanker.rb +6 -0
- data/test/cli_test.rb +25 -0
- data/test/fixtures/result.csv +7 -0
- data/test/fixtures/transactions-with-non-euro.csv +32 -0
- data/test/fixtures/transactions.csv +32 -0
- data/test/test_helper.rb +13 -0
- data/volksbanker.gemspec +22 -0
- metadata +85 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/README.md
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
# Volksbanker
|
2
|
+
|
3
|
+
Prepares Volksbank's electronic statements for upload to Freeagent.
|
4
|
+
|
5
|
+
|
6
|
+
## Usage
|
7
|
+
|
8
|
+
vb STATEMENT > out.csv
|
9
|
+
|
10
|
+
where STATEMENT is your electronic statement from Volksbank, and `out.csv` is the file you'll upload to Freeagent.
|
11
|
+
|
12
|
+
|
13
|
+
## Installation
|
14
|
+
|
15
|
+
gem install volksbanker
|
16
|
+
|
17
|
+
|
18
|
+
## Intellectual property
|
19
|
+
|
20
|
+
Copyright 2012 Andrew Stewart, AirBlade Software Ltd.
|
21
|
+
|
22
|
+
Released under the MIT licence.
|
23
|
+
|
data/Rakefile
ADDED
data/bin/vb
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
module Volksbanker
|
2
|
+
|
3
|
+
class AmexLineItem
|
4
|
+
DATE_FORMAT = '%d/%m/%Y'
|
5
|
+
|
6
|
+
attr_reader :amount, :description
|
7
|
+
|
8
|
+
def initialize(date, amount, description)
|
9
|
+
@date = date
|
10
|
+
@amount = amount
|
11
|
+
@description = description
|
12
|
+
end
|
13
|
+
|
14
|
+
def date
|
15
|
+
@date.strftime DATE_FORMAT
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'volksbanker/volksbank_file_reader'
|
2
|
+
|
3
|
+
module Volksbanker
|
4
|
+
|
5
|
+
class Cli
|
6
|
+
def self.run(volksbank_file)
|
7
|
+
reader = VolksbankFileReader.new volksbank_file
|
8
|
+
reader.each_line_item do |vli|
|
9
|
+
unless vli.currency == 'EUR'
|
10
|
+
$stderr.puts "Skipping non-EUR currency line item: #{vli.inspect}"
|
11
|
+
next
|
12
|
+
end
|
13
|
+
ali = AmexLineItem.new vli.posting_date, vli.value, vli.description
|
14
|
+
CSV { |out| out << [ali.date, ali.amount, ali.description] }
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
# Volksbank format line by line:
|
2
|
+
#
|
3
|
+
# Lines 1-13: header
|
4
|
+
# Subsequent non-blank lines: semi-colon separated values
|
5
|
+
# posting date
|
6
|
+
# value date
|
7
|
+
# payer/payee
|
8
|
+
# recipient/payer
|
9
|
+
# account no.
|
10
|
+
# sortcode
|
11
|
+
# description
|
12
|
+
# currency
|
13
|
+
# amount
|
14
|
+
# credit (H) /debit (S)
|
15
|
+
# Blank line
|
16
|
+
# Footer (opening and closing balances)
|
17
|
+
|
18
|
+
require 'volksbanker/volksbank_line_item'
|
19
|
+
require 'volksbanker/amex_line_item'
|
20
|
+
|
21
|
+
module Volksbanker
|
22
|
+
|
23
|
+
class VolksbankFileReader
|
24
|
+
def initialize(file)
|
25
|
+
@file = file
|
26
|
+
end
|
27
|
+
|
28
|
+
# Yields each transaction line item to the block.
|
29
|
+
# I.e. skips the header and footer information.
|
30
|
+
def each_line_item(&block)
|
31
|
+
data = File.open(@file,'r:iso-8859-1:utf-8') { |f| f.read }
|
32
|
+
data = clean_line_breaks data
|
33
|
+
|
34
|
+
line_number = 0
|
35
|
+
data.each_line do |line|
|
36
|
+
line_number += 1 # 1-based line numbering
|
37
|
+
next if line_number <= 13 # skip header
|
38
|
+
line.chomp!
|
39
|
+
break if line.empty? # skip footer
|
40
|
+
|
41
|
+
yield VolksbankLineItem.new_from_csv line
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
private
|
46
|
+
|
47
|
+
def clean_line_breaks(str)
|
48
|
+
# Format uses \r\n for line breaks between inter-line breaks and \n for intra-line breaks.
|
49
|
+
# There must be a neat Ruby way to do this...
|
50
|
+
remove_inter_line_breaks remove_intra_line_breaks(str)
|
51
|
+
end
|
52
|
+
|
53
|
+
def remove_intra_line_breaks(str)
|
54
|
+
str.gsub /([^\r])\n/, '\1 '
|
55
|
+
end
|
56
|
+
|
57
|
+
def remove_inter_line_breaks(str)
|
58
|
+
str.gsub "\r\n", "\n"
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
require 'csv'
|
2
|
+
|
3
|
+
class VolksbankLineItem
|
4
|
+
DATE_FORMAT = '%d.%m.%Y'
|
5
|
+
|
6
|
+
attr_reader :posting_date, :value_date, :payer_or_payee, :recipient_or_payer,
|
7
|
+
:account_number, :sort_code, :description, :currency,
|
8
|
+
:value
|
9
|
+
|
10
|
+
def initialize(posting_date, value_date, payer_or_payee, recipient_or_payer,
|
11
|
+
account_number, sort_code, description, currency,
|
12
|
+
amount, credit_or_debit)
|
13
|
+
@posting_date = parse_date posting_date
|
14
|
+
@value_date = parse_date value_date
|
15
|
+
@payer_or_payee = payer_or_payee
|
16
|
+
@recipient_or_payer = recipient_or_payer
|
17
|
+
@account_number = account_number
|
18
|
+
@sort_code = sort_code
|
19
|
+
@description = description
|
20
|
+
@currency = currency
|
21
|
+
amt = parse_number amount
|
22
|
+
@value = credit?(credit_or_debit) ? amt : (amt * -1)
|
23
|
+
end
|
24
|
+
|
25
|
+
def self.new_from_csv(line)
|
26
|
+
CSV.parse(line, col_sep: ';') { |row| return new(*row) }
|
27
|
+
end
|
28
|
+
|
29
|
+
private
|
30
|
+
|
31
|
+
def parse_date(str)
|
32
|
+
Date.strptime str, DATE_FORMAT
|
33
|
+
end
|
34
|
+
|
35
|
+
def parse_number(str)
|
36
|
+
str. # There must be a better way to do this!
|
37
|
+
gsub('.', ''). # no thousand-separator
|
38
|
+
gsub(',', '.'). # use decimal point instead of comma for decimal separator
|
39
|
+
to_f
|
40
|
+
end
|
41
|
+
|
42
|
+
def credit?(str)
|
43
|
+
str == 'H'
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
data/lib/volksbanker.rb
ADDED
data/test/cli_test.rb
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'minitest/autorun'
|
2
|
+
require 'test_helper'
|
3
|
+
require 'volksbanker/cli'
|
4
|
+
|
5
|
+
class CliTest < MiniTest::Unit::TestCase
|
6
|
+
|
7
|
+
def test_happy_path
|
8
|
+
expected_stdout = read_fixture 'result.csv'
|
9
|
+
expected_stderr = ''
|
10
|
+
|
11
|
+
assert_output expected_stdout, expected_stderr do
|
12
|
+
Volksbanker::Cli.run fixture('transactions.csv')
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def test_skips_non_euro_line_items
|
17
|
+
out, err = capture_io do
|
18
|
+
Volksbanker::Cli.run fixture('transactions-with-non-euro.csv')
|
19
|
+
end
|
20
|
+
|
21
|
+
refute_match %r{30/07/2012}m, out
|
22
|
+
assert_match /Skipping/, err
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
@@ -0,0 +1,7 @@
|
|
1
|
+
08/08/2012,-7.5,Bankcard-Gebühr FOLGE-NR. 0 VERFALL 12.15 PREIS BEZAHLT BIS 12.2012
|
2
|
+
08/08/2012,170.0,Vergütung INVOICE 7004
|
3
|
+
07/08/2012,170.0,"Vergütung INVOICE 7003 Acme GmbH, JULY 2012"
|
4
|
+
03/08/2012,2023.0,Vergütung INVOICE 7002
|
5
|
+
31/07/2012,68.0,Vergütung RGNR. 2271
|
6
|
+
30/07/2012,136.0,Vergütung INVOICE 7002
|
7
|
+
17/07/2012,170.0,Vergütung INVOICE 2264
|
@@ -0,0 +1,32 @@
|
|
1
|
+
"Volksbank Rhein-Wehra eG"
|
2
|
+
|
3
|
+
"Umsatzanzeige"
|
4
|
+
|
5
|
+
"BLZ:";"68490000";;"Datum:";"13.08.2012"
|
6
|
+
"Konto:";"12345678";;"Uhrzeit:";"11:54:07"
|
7
|
+
"Abfrage von:";"Joe Bloggs";;"Kontoinhaber:";"Foo GmbH"
|
8
|
+
|
9
|
+
"Zeitraum:";"4 Wochen";"von:";;"bis:";
|
10
|
+
"Betrag in EUR:";;"von:";" ";"bis:";" "
|
11
|
+
"Sortiert nach:";"Buchungstag";"absteigend"
|
12
|
+
|
13
|
+
"Buchungstag";"Valuta";"Auftraggeber/Zahlungsempf�nger";"Empf�nger/Zahlungspflichtiger";"Konto-Nr.";"BLZ";"Vorgang/Verwendungszweck";"W�hrung";"Umsatz";" "
|
14
|
+
"08.08.2012";"08.08.2012";;"PREIS VR-BANKCARD";"1234500000";"12340000";"Bankcard-Geb�hr
|
15
|
+
FOLGE-NR. 0 VERFALL 12.15
|
16
|
+
PREIS BEZAHLT BIS 12.2012";"EUR";"7,50";"S"
|
17
|
+
"08.08.2012";"08.08.2012";"Foo GmbH";"Jane Doe";"1234567890";"12345678";"Verg�tung
|
18
|
+
INVOICE 7004";"EUR";"170,00";"H"
|
19
|
+
"07.08.2012";"07.08.2012";"BarApp";"Sarah Smith";"123456789";"12345678";"Verg�tung
|
20
|
+
INVOICE 7003
|
21
|
+
Acme GmbH, JULY 2012";"EUR";"170,00";"H"
|
22
|
+
"03.08.2012";"03.08.2012";"Foo GmbH";"Some Firm GmbH";"1234567";"12345678";"Verg�tung
|
23
|
+
INVOICE 7002";"EUR";"2.023,00";"H"
|
24
|
+
"31.07.2012";"31.07.2012";"Foo GmbH";"James Brown";"1234567890";"12345678";"Verg�tung
|
25
|
+
RGNR. 2271";"EUR";"68,00";"H"
|
26
|
+
"30.07.2012";"30.07.2012";"Foo GmbH";"Example.com";"123456789";"12345678";"Verg�tung
|
27
|
+
INVOICE 7002";"GBP";"136,00";"H"
|
28
|
+
"17.07.2012";"17.07.2012";"Foo GmbH";"Blah Inc GmbH";"1234567890";"12345678";"Verg�tung
|
29
|
+
INVOICE 2264";"EUR";"170,00";"H"
|
30
|
+
|
31
|
+
"17.07.2012";;;;;;"EUR";"Anfangssaldo";"0,00";"H"
|
32
|
+
"08.08.2012";;;;;;"EUR";"Endsaldo";"2.729,50";"H"
|
@@ -0,0 +1,32 @@
|
|
1
|
+
"Volksbank Rhein-Wehra eG"
|
2
|
+
|
3
|
+
"Umsatzanzeige"
|
4
|
+
|
5
|
+
"BLZ:";"68490000";;"Datum:";"13.08.2012"
|
6
|
+
"Konto:";"12345678";;"Uhrzeit:";"11:54:07"
|
7
|
+
"Abfrage von:";"Joe Bloggs";;"Kontoinhaber:";"Foo GmbH"
|
8
|
+
|
9
|
+
"Zeitraum:";"4 Wochen";"von:";;"bis:";
|
10
|
+
"Betrag in EUR:";;"von:";" ";"bis:";" "
|
11
|
+
"Sortiert nach:";"Buchungstag";"absteigend"
|
12
|
+
|
13
|
+
"Buchungstag";"Valuta";"Auftraggeber/Zahlungsempf�nger";"Empf�nger/Zahlungspflichtiger";"Konto-Nr.";"BLZ";"Vorgang/Verwendungszweck";"W�hrung";"Umsatz";" "
|
14
|
+
"08.08.2012";"08.08.2012";;"PREIS VR-BANKCARD";"1234500000";"12340000";"Bankcard-Geb�hr
|
15
|
+
FOLGE-NR. 0 VERFALL 12.15
|
16
|
+
PREIS BEZAHLT BIS 12.2012";"EUR";"7,50";"S"
|
17
|
+
"08.08.2012";"08.08.2012";"Foo GmbH";"Jane Doe";"1234567890";"12345678";"Verg�tung
|
18
|
+
INVOICE 7004";"EUR";"170,00";"H"
|
19
|
+
"07.08.2012";"07.08.2012";"BarApp";"Sarah Smith";"123456789";"12345678";"Verg�tung
|
20
|
+
INVOICE 7003
|
21
|
+
Acme GmbH, JULY 2012";"EUR";"170,00";"H"
|
22
|
+
"03.08.2012";"03.08.2012";"Foo GmbH";"Some Firm GmbH";"1234567";"12345678";"Verg�tung
|
23
|
+
INVOICE 7002";"EUR";"2.023,00";"H"
|
24
|
+
"31.07.2012";"31.07.2012";"Foo GmbH";"James Brown";"1234567890";"12345678";"Verg�tung
|
25
|
+
RGNR. 2271";"EUR";"68,00";"H"
|
26
|
+
"30.07.2012";"30.07.2012";"Foo GmbH";"Example.com";"123456789";"12345678";"Verg�tung
|
27
|
+
INVOICE 7002";"EUR";"136,00";"H"
|
28
|
+
"17.07.2012";"17.07.2012";"Foo GmbH";"Blah Inc GmbH";"1234567890";"12345678";"Verg�tung
|
29
|
+
INVOICE 2264";"EUR";"170,00";"H"
|
30
|
+
|
31
|
+
"17.07.2012";;;;;;"EUR";"Anfangssaldo";"0,00";"H"
|
32
|
+
"08.08.2012";;;;;;"EUR";"Endsaldo";"2.729,50";"H"
|
data/test/test_helper.rb
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
class MiniTest::Unit::TestCase
|
2
|
+
|
3
|
+
# Returns full path to fixture file.
|
4
|
+
def fixture(filename)
|
5
|
+
File.expand_path "../fixtures/#{filename}", __FILE__
|
6
|
+
end
|
7
|
+
|
8
|
+
# Returns contents of fixture file.
|
9
|
+
def read_fixture(filename)
|
10
|
+
File.open(fixture filename) { |f| f.read }
|
11
|
+
end
|
12
|
+
|
13
|
+
end
|
data/volksbanker.gemspec
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "volksbanker/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "volksbanker"
|
7
|
+
s.version = Volksbanker::VERSION
|
8
|
+
s.authors = ["Andy Stewart"]
|
9
|
+
s.email = ["boss@airbladesoftware.com"]
|
10
|
+
s.homepage = ""
|
11
|
+
s.summary = "Prepares Volksbank's electronic statements for upload to Freeagent."
|
12
|
+
s.description = s.summary
|
13
|
+
|
14
|
+
s.rubyforge_project = "volksbanker"
|
15
|
+
|
16
|
+
s.files = `git ls-files`.split("\n")
|
17
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
18
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
19
|
+
s.require_paths = ["lib"]
|
20
|
+
|
21
|
+
s.add_development_dependency 'rake', '~> 0.9.2'
|
22
|
+
end
|
metadata
ADDED
@@ -0,0 +1,85 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: volksbanker
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Andy Stewart
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-08-28 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: rake
|
16
|
+
requirement: &2159222460 !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ~>
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: 0.9.2
|
22
|
+
type: :development
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: *2159222460
|
25
|
+
description: Prepares Volksbank's electronic statements for upload to Freeagent.
|
26
|
+
email:
|
27
|
+
- boss@airbladesoftware.com
|
28
|
+
executables:
|
29
|
+
- vb
|
30
|
+
extensions: []
|
31
|
+
extra_rdoc_files: []
|
32
|
+
files:
|
33
|
+
- .gitignore
|
34
|
+
- Gemfile
|
35
|
+
- README.md
|
36
|
+
- Rakefile
|
37
|
+
- bin/vb
|
38
|
+
- lib/volksbanker.rb
|
39
|
+
- lib/volksbanker/amex_line_item.rb
|
40
|
+
- lib/volksbanker/cli.rb
|
41
|
+
- lib/volksbanker/version.rb
|
42
|
+
- lib/volksbanker/volksbank_file_reader.rb
|
43
|
+
- lib/volksbanker/volksbank_line_item.rb
|
44
|
+
- test/cli_test.rb
|
45
|
+
- test/fixtures/result.csv
|
46
|
+
- test/fixtures/transactions-with-non-euro.csv
|
47
|
+
- test/fixtures/transactions.csv
|
48
|
+
- test/test_helper.rb
|
49
|
+
- volksbanker.gemspec
|
50
|
+
homepage: ''
|
51
|
+
licenses: []
|
52
|
+
post_install_message:
|
53
|
+
rdoc_options: []
|
54
|
+
require_paths:
|
55
|
+
- lib
|
56
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ! '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
segments:
|
63
|
+
- 0
|
64
|
+
hash: 3400310575893115125
|
65
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
66
|
+
none: false
|
67
|
+
requirements:
|
68
|
+
- - ! '>='
|
69
|
+
- !ruby/object:Gem::Version
|
70
|
+
version: '0'
|
71
|
+
segments:
|
72
|
+
- 0
|
73
|
+
hash: 3400310575893115125
|
74
|
+
requirements: []
|
75
|
+
rubyforge_project: volksbanker
|
76
|
+
rubygems_version: 1.8.11
|
77
|
+
signing_key:
|
78
|
+
specification_version: 3
|
79
|
+
summary: Prepares Volksbank's electronic statements for upload to Freeagent.
|
80
|
+
test_files:
|
81
|
+
- test/cli_test.rb
|
82
|
+
- test/fixtures/result.csv
|
83
|
+
- test/fixtures/transactions-with-non-euro.csv
|
84
|
+
- test/fixtures/transactions.csv
|
85
|
+
- test/test_helper.rb
|