volksbanker 1.0.4 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 0974b24b904b345fba255068d2d509fc58710e4a
4
- data.tar.gz: 92bc379948ef9e2f826b278b1cecc85efc604284
3
+ metadata.gz: ad7b5c087408c0c564998c96cbfeb0d6ea97b56f
4
+ data.tar.gz: a489a03d32b625f17c106fe0c9e24345aeda086a
5
5
  SHA512:
6
- metadata.gz: 538a132b9cb1905ab06768ad4bd2b9542ea70b1b214f32befd05c71e27d288a6398c361b37b02160bf5e172d8e12ff76b0250a707f7b8838eb31bb258d4bc42a
7
- data.tar.gz: 8534960cd83158ced59971b0dbd95338d4eceddbd9b33a1f9ecca40f85dde45c5ec9d1c1337b8b157110d51814bb3e8574b21dd573d81ef4bd0fc5326729848a
6
+ metadata.gz: b41bdc37a6925cdd20b14cd4e33b4bf74490868fd06d13244ed2cab844ee4569751803f2f678b362a953b535a70ca21d6a021a5aa7f26d1d3823ca346e12e48e
7
+ data.tar.gz: b2c01bfcb3e017cf0f41da29e76c87a707a6c74d3cefdd2a059c71bab04b85540d707cda37a95012659639368b73f5788c00f0eb55eca4fb165174660b47162d
@@ -0,0 +1,18 @@
1
+ require 'csv'
2
+ require 'volksbanker/line'
3
+
4
+ module Volksbanker
5
+ class Balance < Line
6
+ attr_reader :amount, :currency, :date
7
+
8
+ def initialize(date, _, _, _, _, _, currency, _, amount, credit_or_debit)
9
+ @date = parse_date date
10
+ @currency = currency
11
+ @amount = parse_amount amount, credit_or_debit
12
+ end
13
+
14
+ def to_s
15
+ "#{date}: #{'%.2f' % amount} #{currency}"
16
+ end
17
+ end
18
+ end
@@ -1,3 +1,4 @@
1
+ require 'volksbanker/statement'
1
2
  require 'volksbanker/volksbank_file_reader'
2
3
  require 'volksbanker/amex_line_item'
3
4
 
@@ -5,30 +6,13 @@ module Volksbanker
5
6
 
6
7
  class Cli
7
8
  def self.run(volksbank_file)
8
- reader = VolksbankFileReader.new volksbank_file
9
- reader.each_line_item do |vli|
10
- ali = AmexLineItem.new vli.posting_date, vli.value, description_for(vli)
11
- case ali.description
12
- when 'Anfangssaldo'; @opening_balance = pretty_amount(ali.amount, vli.currency)
13
- when 'Endsaldo'; @closing_balance = pretty_amount(ali.amount, vli.currency)
14
- else
15
- CSV { |out| out << [ali.date, ali.amount, ali.description] }
16
- end
9
+ statement = VolksbankFileReader.new(volksbank_file).statement
10
+ statement.transactions.each do |transaction|
11
+ ali = AmexLineItem.new transaction.posting_date, transaction.amount, transaction.description_with_counterparty
12
+ CSV { |out| out << [ali.date, ali.amount, ali.description] }
17
13
  end
18
- $stderr.puts "opening balance: #{@opening_balance}"
19
- $stderr.puts "closing balance: #{@closing_balance}"
20
- end
21
-
22
- private
23
-
24
- def self.description_for(volksbank_line_item)
25
- desc = volksbank_line_item.description
26
- desc += " (#{volksbank_line_item.recipient_or_payer})" unless volksbank_line_item.recipient_or_payer.nil?
27
- desc
28
- end
29
-
30
- def self.pretty_amount(amount, currency)
31
- "#{'%.2f' % amount} #{currency}"
14
+ $stderr.puts "opening balance: #{statement.opening_balance}"
15
+ $stderr.puts "closing balance: #{statement.closing_balance}"
32
16
  end
33
17
  end
34
18
 
@@ -0,0 +1,34 @@
1
+ require 'csv'
2
+
3
+ module Volksbanker
4
+ class Line
5
+ DATE_FORMAT = '%d.%m.%Y'
6
+
7
+ def self.parse(str)
8
+ CSV.parse(str, col_sep: ';') { |row| return new(*row) }
9
+ end
10
+
11
+ def parse_date(str)
12
+ Date.strptime str, DATE_FORMAT if str
13
+ end
14
+
15
+ def parse_amount(amt, dir)
16
+ amount = parse_number amt
17
+ amount *= -1 unless credit?(dir)
18
+ amount
19
+ end
20
+
21
+ private
22
+
23
+ def parse_number(str)
24
+ str. # There must be a better way to do this!
25
+ gsub('.', ''). # no thousand-separator
26
+ gsub(',', '.'). # use decimal point instead of comma for decimal separator
27
+ to_f
28
+ end
29
+
30
+ def credit?(str)
31
+ str == 'H'
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,12 @@
1
+ module Volksbanker
2
+ class Statement
3
+ attr_reader :transactions, :opening_balance, :closing_balance
4
+
5
+ def initialize(transactions, opening_balance, closing_balance)
6
+ @transactions = transactions
7
+ @opening_balance = opening_balance
8
+ @closing_balance = closing_balance
9
+ end
10
+
11
+ end
12
+ end
@@ -0,0 +1,48 @@
1
+ require 'csv'
2
+
3
+ module Volksbanker
4
+
5
+ # A transaction has the following fields on the Volksbank download:
6
+ #
7
+ # posting date
8
+ # value date
9
+ # payer/payee
10
+ # recipient/payer
11
+ # account no.
12
+ # iban
13
+ # sortcode (BLZ)
14
+ # sortcode (BIC)
15
+ # description
16
+ # reference
17
+ # currency
18
+ # amount
19
+ # credit (H) / debit (S)
20
+ class Transaction < Line
21
+ attr_reader :posting_date, :value_date, :payer_or_payee, :recipient_or_payer,
22
+ :account_number, :iban, :sort_code, :bic, :description, :reference, :currency,
23
+ :amount
24
+
25
+ def initialize(posting_date, value_date, payer_or_payee, recipient_or_payer,
26
+ account_number, iban, sort_code, bic, description, reference, currency,
27
+ amount, credit_or_debit)
28
+ @posting_date = parse_date posting_date
29
+ @value_date = parse_date value_date
30
+ @payer_or_payee = payer_or_payee
31
+ @recipient_or_payer = recipient_or_payer
32
+ @account_number = account_number
33
+ @iban = iban
34
+ @sort_code = sort_code
35
+ @bic = bic
36
+ @description = description
37
+ @reference = reference
38
+ @currency = currency
39
+ @amount = parse_amount amount, credit_or_debit
40
+ end
41
+
42
+ def description_with_counterparty
43
+ x = description
44
+ x += " (#{recipient_or_payer})" unless recipient_or_payer.nil?
45
+ x
46
+ end
47
+ end
48
+ end
@@ -1,3 +1,3 @@
1
1
  module Volksbanker
2
- VERSION = '1.0.4'
2
+ VERSION = '1.1.0'
3
3
  end
@@ -1,39 +1,37 @@
1
- # Volksbank format line by line:
2
- #
3
- # Header information including blank lines.
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'
1
+ require 'volksbanker/statement'
2
+ require 'volksbanker/balance'
3
+ require 'volksbanker/transaction'
19
4
 
20
5
  module Volksbanker
21
6
 
22
7
  class VolksbankFileReader
23
8
  def initialize(file)
24
9
  @file = file
10
+ read
25
11
  end
26
12
 
27
- # Yields each transaction line item to the block.
28
- # I.e. skips the header and footer information.
29
- def each_line_item(&block)
30
- data = File.open(@file,'r:iso-8859-1:utf-8') { |f| f.read }
31
- data = clean_line_breaks data
13
+ def statement
14
+ Statement.new @line_items, @opening_balance, @closing_balance
15
+ end
16
+
17
+ private
18
+
19
+ def read
20
+ # Layout of file:
21
+ # Header information including blank lines.
22
+ # Subsequent non-blank lines: transactions.
23
+ # Blank line
24
+ # Opening balance
25
+ # Closing balance
32
26
 
27
+ @line_items = []
33
28
  header = true
29
+
30
+ data = File.open(@file,'r:iso-8859-1:utf-8') { |f| f.read }
31
+ data = clean_line_breaks data
34
32
  data.each_line do |line|
35
33
  # skip header
36
- if line =~ /^"Buchungstag";"Valuta";/ # final line of header
34
+ if last_line_of_header? line
37
35
  header = false
38
36
  next
39
37
  end
@@ -41,13 +39,29 @@ module Volksbanker
41
39
 
42
40
  line.chomp!
43
41
 
44
- unless line.empty?
45
- yield VolksbankLineItem.new_from_csv line rescue $stderr.puts "Problem with #{line}: #{$!}"
42
+ if opening_balance? line
43
+ @opening_balance = Balance.parse line
44
+ elsif closing_balance? line
45
+ @closing_balance = Balance.parse line
46
+ else
47
+ unless line.empty?
48
+ @line_items << Transaction.parse(line) rescue $stderr.puts "Problem with #{line}: #{$!}"
49
+ end
46
50
  end
47
51
  end
48
52
  end
49
53
 
50
- private
54
+ def last_line_of_header?(str)
55
+ str =~ /^"Buchungstag";"Valuta";/
56
+ end
57
+
58
+ def opening_balance?(str)
59
+ str =~ /;"Anfangssaldo";/
60
+ end
61
+
62
+ def closing_balance?(str)
63
+ str =~ /;"Endsaldo";/
64
+ end
51
65
 
52
66
  def clean_line_breaks(str)
53
67
  # Format uses CRLF (\r\n) for line breaks and LF (\n) for intra-line breaks (whatever
@@ -10,10 +10,10 @@
10
10
  "Betrag in EUR:";;"von:";" ";"bis:";" "
11
11
  "Sortiert nach:";"Buchungstag";"absteigend"
12
12
 
13
- "Buchungstag";"Valuta";"Auftraggeber/Zahlungsempf�nger";"Empf�nger/Zahlungspflichtiger";"Konto-Nr.";"BLZ";"Vorgang/Verwendungszweck";"W�hrung";"Umsatz";" "
14
- "02.10.2012";"30.09.2012";;;;;"Abschluss
13
+ "Buchungstag";"Valuta";"Auftraggeber/Zahlungsempf�nger";"Empf�nger/Zahlungspflichtiger";"Konto-Nr.";"IBAN";"BLZ";"BIC";"Vorgang/Verwendungszweck";"Kundenreferenz";"W�hrung";"Umsatz";" "
14
+ "02.10.2012";"30.09.2012";;;;;;;"Abschluss
15
15
 
16
- ABSCHLUSS PER 30.09.2012";"EUR";"10,27";"S"
16
+ ABSCHLUSS PER 30.09.2012";;"EUR";"10,27";"S"
17
17
 
18
18
  "01.10.2012";;;;;;"EUR";"Anfangssaldo";"1.234,56";"H"
19
19
  "05.10.2012";;;;;;"EUR";"Endsaldo";"3.456,67";"H"
@@ -1,2 +1,2 @@
1
- opening balance: 1234.56 EUR
2
- closing balance: 3456.67 EUR
1
+ opening balance: 2012-10-01: 1234.56 EUR
2
+ closing balance: 2012-10-05: 3456.67 EUR
@@ -1,2 +1,2 @@
1
- opening balance: 0.00 EUR
2
- closing balance: 2729.50 EUR
1
+ opening balance: 2012-07-17: 0.00 EUR
2
+ closing balance: 2012-08-08: 2729.50 EUR
@@ -10,23 +10,23 @@
10
10
  "Betrag in EUR:";;"von:";" ";"bis:";" "
11
11
  "Sortiert nach:";"Buchungstag";"absteigend"
12
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
13
+ "Buchungstag";"Valuta";"Auftraggeber/Zahlungsempf�nger";"Empf�nger/Zahlungspflichtiger";"Konto-Nr.";"IBAN";"BLZ";"BIC";"Vorgang/Verwendungszweck";"Kundenreferenz";"W�hrung";"Umsatz";" "
14
+ "08.08.2012";"08.08.2012";;"PREIS VR-BANKCARD";"1234500000";"this is an iban";"12340000";"bic";"Bankcard-Geb�hr
15
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
16
+ PREIS BEZAHLT BIS 12.2012";"ref";"EUR";"7,50";"S"
17
+ "08.08.2012";"08.08.2012";"Foo GmbH";"Jane Doe";"1234567890";"this is an iban";"12345678";"bic";"Verg�tung
18
+ INVOICE 7004";"ref";"EUR";"170,00";"H"
19
+ "07.08.2012";"07.08.2012";"BarApp";"Sarah Smith";"123456789";"this is an iban";"12345678";"bic";"Verg�tung
20
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"
21
+ Acme GmbH, JULY 2012";"ref";"EUR";"170,00";"H"
22
+ "03.08.2012";"03.08.2012";"Foo GmbH";"Some Firm GmbH";"1234567";"this is an iban";"12345678";"bic";"Verg�tung
23
+ INVOICE 7002";"ref";"EUR";"2.023,00";"H"
24
+ "31.07.2012";"31.07.2012";"Foo GmbH";"James Brown";"1234567890";"this is an iban";"12345678";"bic";"Verg�tung
25
+ RGNR. 2271";"ref";"EUR";"68,00";"H"
26
+ "30.07.2012";"30.07.2012";"Foo GmbH";"Example.com";"123456789";"this is an iban";"12345678";"bic";"Verg�tung
27
+ INVOICE 7002";"ref";"EUR";"136,00";"H"
28
+ "17.07.2012";"17.07.2012";"Foo GmbH";"Blah Inc GmbH";"1234567890";"this is an iban";"12345678";"bic";"Verg�tung
29
+ INVOICE 2264";"ref";"EUR";"170,00";"H"
30
30
 
31
31
  "17.07.2012";;;;;;"EUR";"Anfangssaldo";"0,00";"H"
32
32
  "08.08.2012";;;;;;"EUR";"Endsaldo";"2.729,50";"H"
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: volksbanker
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.4
4
+ version: 1.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andy Stewart
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-10-21 00:00:00.000000000 Z
11
+ date: 2015-07-08 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rake
@@ -40,10 +40,13 @@ files:
40
40
  - bin/vb
41
41
  - lib/volksbanker.rb
42
42
  - lib/volksbanker/amex_line_item.rb
43
+ - lib/volksbanker/balance.rb
43
44
  - lib/volksbanker/cli.rb
45
+ - lib/volksbanker/line.rb
46
+ - lib/volksbanker/statement.rb
47
+ - lib/volksbanker/transaction.rb
44
48
  - lib/volksbanker/version.rb
45
49
  - lib/volksbanker/volksbank_file_reader.rb
46
- - lib/volksbanker/volksbank_line_item.rb
47
50
  - test/cli_test.rb
48
51
  - test/fixtures/newlines.csv
49
52
  - test/fixtures/newlines.stderr.csv
@@ -1,53 +0,0 @@
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
-
20
- @description = description
21
- @currency = currency
22
- # The opening and closing balance lines switch the currency and description fields.
23
- if %w[ Anfangssaldo Endsaldo ].include? currency
24
- @description = currency
25
- @currency = description
26
- end
27
-
28
- amt = parse_number amount
29
- @value = credit?(credit_or_debit) ? amt : (amt * -1)
30
- end
31
-
32
- def self.new_from_csv(line)
33
- CSV.parse(line, col_sep: ';') { |row| return new(*row) }
34
- end
35
-
36
- private
37
-
38
- def parse_date(str)
39
- Date.strptime str, DATE_FORMAT if str
40
- end
41
-
42
- def parse_number(str)
43
- str. # There must be a better way to do this!
44
- gsub('.', ''). # no thousand-separator
45
- gsub(',', '.'). # use decimal point instead of comma for decimal separator
46
- to_f
47
- end
48
-
49
- def credit?(str)
50
- str == 'H'
51
- end
52
- end
53
-