dtaus 0.1.1 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
data/README.markdown CHANGED
@@ -1,8 +1,8 @@
1
1
  DTAUS
2
2
  =====
3
3
 
4
- This is a library specific to the german banking sector. Therefore the documentation will be in german. If you have any questions please feel free to email me at mikezter@gmail.com
5
-
4
+ This is a library specific to the german banking sector. Therefore the documentation will be in german. If you have any questions please feel free to email me at mikezter@gmail.com
5
+
6
6
  Beim Datenträgeraustausch (DTA) werden Zahlungsverkehrsdaten - also Überweisungen und Lastschriften - als Datei an ein Geldinstitut übergeben. Dieser Gem stellt Klassen bereit solche Dateien zu erzeugen.
7
7
 
8
8
  Download
@@ -16,46 +16,63 @@ Usage
16
16
  Ablauf:
17
17
 
18
18
  * Erstelle ein Auftraggeber-Konto
19
- * Erstelle ein DTAUS Objekt für diesen Auftraggeber
19
+ * Erstelle ein Datensatz für diesen Auftraggeber
20
20
  * Erstelle ein oder mehrerere Kunden-Konten mit dazugehörigen Buchungen
21
- * Füge die Buchungen dem DTAUS Objekt hinzu
22
- * Schreibe eine DTAUS Datei
23
- * _Alternativ:_ Gebe die Daten als String aus
21
+ * Füge die Buchungen dem Datensatz hinzu
22
+ * Schreibe den Datensatz als DTAUS Datei
23
+ * _Alternativ:_ Gib die Daten als String aus
24
24
 
25
25
  In Ruby:
26
26
 
27
- auftraggeber = DTAUS::Konto.new(1234567890, 12345670, 'Muster GmbH', 'Deutsche Bank', true)
28
-
29
- dta = DTAUS.new(auftraggeber)
30
-
31
- kunde = DTAUS::Konto.new(1234567890, 12345670, 'Max Meier-Schulze', 'Sparkasse')
32
- buchung = DTAUS::Buchung.new(auftraggeber, kunde, 39.99, 'Vielen Dank für ihren Einkauf vom 01.01.2010. Rechnungsnummer 12345')
33
-
34
- dta.add(buchung)
35
-
36
- dta.to_file
37
-
38
- puts dta
39
-
27
+ ``` ruby
28
+ require 'dtaus'
29
+
30
+ # Konto des Auftraggebers
31
+ konto_auftraggeber = DTAUS::Konto.new(
32
+ :kontonummer => 1234567890,
33
+ :blz => 82070024,
34
+ :kontoinhaber => 'inoxio Quality Services GmbH',
35
+ :bankname =>'Deutsche Bank',
36
+ :is_auftraggeber => true
37
+ )
38
+
39
+ # LASTSCHRIFT
40
+ # Erstellen eines Datensatzes für eine Lastschrift
41
+ lastschrift = DTAUS::Datensatz.new(:lastschrift, konto_auftraggeber)
42
+
43
+ # Konto des Kunden
44
+ konto_kunde = DTAUS::Konto.new(
45
+ :kontonummer => 1234567890,
46
+ :blz => 12030000,
47
+ :kontoinhaber => 'Max Meier-Schulze',
48
+ :bankname =>'Sparkasse',
49
+ :kundennummer => 77777777777
50
+ )
51
+ # Lastschrift-Buchung für den Kunden
52
+ buchung = DTAUS::Buchung.new(
53
+ :kunden_konto => konto_kunde,
54
+ :betrag => "9,99",
55
+ :transaktionstyp => :lastschrift,
56
+ :verwendungszweck => "Vielen Dank für Ihren Einkauf!"
57
+ )
58
+ lastschrift.add(buchung)
59
+
60
+ lastschrift.to_file
61
+ puts lastschrift
62
+ ```
63
+
64
+ Siehe: [example/example.rb](https://github.com/alphaone/dtaus/blob/master/example/example.rb)
40
65
 
41
66
  Einschränkungen:
42
67
  ----------------
43
68
 
44
- * Es sind nur Lastschriften möglich. __Typ der Datei ist LK__ (Lastschrift Kunde).
69
+ * Es sind nur Lastschriften und Gutschriften möglich. __Typ der Datei ist LK oder GK__ (Lastschrift-Kunde oder Gutschrift-Kunde).
45
70
  * Auftraggeber, Empfänger und Verwendungszweck können jeweils 27 Zeichen enthalten. Es stehen 15 Erweiterungen à 27 Zeichen zur Verfügung. Jede Erweiterung kann entweder Auftraggeber, Empfänger oder Verwendungszweck erweitern.
46
71
 
47
- Todo:
48
- ------
49
-
50
- * Gutschriften ermöglichen
51
- * Refactor to Module instead of Class with Subclasses
52
- * Parameter als Hash annehmen (vor allem für `Konto` und `Buchung`)
53
- * weiteres?
54
-
55
72
  Weitere Informationen
56
73
  ---------------------
57
-
74
+
58
75
  Infos zu DTAUS: http://www.infodrom.org/projects/dtaus/dtaus.html
59
-
76
+
60
77
  DTAUS online check: http://www.xpecto.de/index.php?id=148,7
61
78
 
data/Rakefile ADDED
@@ -0,0 +1,23 @@
1
+ require 'rake'
2
+ require 'rake/testtask'
3
+ require 'rake/rdoctask'
4
+
5
+ desc 'Default: run unit tests.'
6
+ task :default => [:test]
7
+
8
+ desc 'Test the dtaus gem.'
9
+ Rake::TestTask.new(:test) do |t|
10
+ t.libs << 'lib' << 'dtaus'
11
+ t.pattern = 'test/**/*_test.rb'
12
+ t.verbose = true
13
+ end
14
+
15
+ desc 'Generate documentation for the dtaus gem.'
16
+ Rake::RDocTask.new(:rdoc) do |rdoc|
17
+ rdoc.rdoc_dir = 'doc'
18
+ rdoc.title = 'DTAUS'
19
+ rdoc.options << '--line-numbers' << '--inline-source'
20
+ rdoc.options << '--charset' << 'utf-8'
21
+ rdoc.rdoc_files.include('README*')
22
+ rdoc.rdoc_files.include('lib/**/*.rb')
23
+ end
@@ -0,0 +1,63 @@
1
+ ROOT = File.join(File.dirname(__FILE__), '..')
2
+ $LOAD_PATH << File.join(ROOT, 'lib')
3
+ $LOAD_PATH << File.join(ROOT, 'lib', 'dtaus')
4
+
5
+ require 'dtaus'
6
+
7
+ # Konto des Auftraggebers
8
+ konto_auftraggeber = DTAUS::Konto.new(
9
+ :kontonummer => 1234567890,
10
+ :blz => 82070024,
11
+ :kontoinhaber => 'inoxio Quality Services GmbH',
12
+ :bankname =>'Deutsche Bank',
13
+ :is_auftraggeber => true
14
+ )
15
+
16
+ # GUTSCHRIFT
17
+ # Erstellen eines Datensatzes für eine Gutschrift
18
+ gutschrift = DTAUS::Datensatz.new(:gutschrift, konto_auftraggeber)
19
+
20
+ # Konto des Kunden
21
+ konto_kunde = DTAUS::Konto.new(
22
+ :kontonummer => 1234567890,
23
+ :blz => 12030000,
24
+ :kontoinhaber => 'Max Meier-Schulze',
25
+ :bankname =>'Sparkasse',
26
+ :kundennummer => 77777777777
27
+ )
28
+ # Gutschrift-Buchung für den Kunden
29
+ buchung = DTAUS::Buchung.new(
30
+ :kunden_konto => konto_kunde,
31
+ :betrag => "9,99",
32
+ :transaktionstyp => :gutschrift,
33
+ :verwendungszweck => "Vielen Dank für Ihren Einkauf!"
34
+ )
35
+ gutschrift.add(buchung)
36
+
37
+ gutschrift.to_file('gutschrift.txt')
38
+ puts gutschrift
39
+
40
+ # LASTSCHRIFT
41
+ # Erstellen eines Datensatzes für eine Lastschrift
42
+ lastschrift = DTAUS::Datensatz.new(:lastschrift, konto_auftraggeber)
43
+
44
+ # Konto des Kunden
45
+ konto_kunde = DTAUS::Konto.new(
46
+ :kontonummer => 1234567890,
47
+ :blz => 12030000,
48
+ :kontoinhaber => 'Max Meier-Schulze',
49
+ :bankname =>'Sparkasse',
50
+ :kundennummer => 77777777777
51
+ )
52
+ # Lastschrift-Buchung für den Kunden
53
+ buchung = DTAUS::Buchung.new(
54
+ :kunden_konto => konto_kunde,
55
+ :betrag => "9,99",
56
+ :transaktionstyp => :lastschrift,
57
+ :verwendungszweck => "Vielen Dank für Ihren Einkauf!"
58
+ )
59
+ lastschrift.add(buchung)
60
+
61
+ lastschrift.to_file('lastschrift.txt')
62
+ puts lastschrift
63
+
data/lib/dtaus/buchung.rb CHANGED
@@ -1,116 +1,82 @@
1
- require 'enumerator'
2
- require 'dtaus/erweiterung'
1
+ # encoding: utf-8
3
2
 
4
- class DTAUS
3
+ module DTAUS
5
4
 
6
- # Buchung erstellen
7
- # buchung = Buchung.new(auftraggeber_konto, kunden_konto, betrag, verwendungszweck)
8
- #
9
- # auftraggeber_konto und kunden_konto müssen ein DTAUS::Konto sein
10
- # betrag muss ein Float sein
11
- #
5
+ # Buchungsdaten mit zwei Konten (Auftraggeber und Kunde),
6
+ # Betrag und Verwendungszweck
12
7
  class Buchung
13
- attr_reader :betrag, :konto, :text, :positiv, :auftraggeber
14
- alias :positiv? :positiv
15
8
 
16
- def initialize(_auftraggeber, _konto, _betrag, _text = "")
17
- raise DTAusException.new("Konto expected, got #{_konto.class}") unless _konto.is_a?(Konto)
18
- raise DTAUSException.new("Betrag is a #{_betrag.class}, expected Float") unless _betrag.is_a?(Float)
19
- raise DTAUSException.new("Betrag ist 0.0") unless _betrag > 0
9
+ attr_reader :betrag, :kunden_konto, :auftraggeber_konto, :verwendungszweck, :positiv, :transaktionstyp
10
+ alias :positiv? :positiv
20
11
 
21
- @auftraggeber = _auftraggeber
22
- @konto = _konto
23
- @text = DTAUS.convert_text(_text)
12
+ # Buchung erstellen
13
+ #
14
+ # +params+ as Hash:
15
+ # [<tt>:kunden_konto</tt>] DTAUS::Konto des Kunden
16
+ # [<tt>:betrag</tt>] der Betrag der Buchung in +Float+
17
+ # [<tt>:transaktionstyp</tt>] Art der Transaktion
18
+ # * <tt>:lastschrift</tt> Lastschrift des Einzugsermächtigungsverfahren
19
+ # * <tt>:gutschrift</tt> Überweisungs-Gutschrift
20
+ # _optional_, Default-Wert ist <tt>:lastschrift</tt>
21
+ # [<tt>:verwendungszweck</tt>] der Verwendungszweck der Buchung; _optional_, Default-Wert ist ""
22
+ def initialize(params = {})
23
+ # defaults
24
+ params = {
25
+ :transaktionstyp => :lastschrift,
26
+ :verwendungszweck => ''
27
+ }.merge(params)
28
+
29
+ [:betrag, :kunden_konto].each do |attr|
30
+ raise ArgumentError.new("Missing params[:#{attr}] for new Buchung.") if params[attr].nil?
31
+ end
24
32
 
25
- raise IncorrectSize.new("Zuviele Erweiterungen: #{erweiterungen.size}, maximal 15. Verwendungszweck zu lang?") if erweiterungen.size > 15
33
+ unless params[:kunden_konto].is_a?(Konto)
34
+ raise DTAUSException.new("Konto expected for Parameter 'kunden_konto', got #{params[:kunden_konto].class}")
35
+ end
36
+ unless [:lastschrift, :gutschrift].include?(params[:transaktionstyp])
37
+ raise DTAUSException.new("Transaktionstyp has to be one of [:lastschrift, :gutschrift]")
38
+ end
26
39
 
27
- @betrag = (_betrag * 100).round.to_i # Euro-Cent
28
- if betrag > 0
29
- @positiv = true
40
+ # betrag to BigDecimal
41
+ if params[:betrag].is_a? String
42
+ params[:betrag] = BigDecimal.new params[:betrag].sub(',', '.')
43
+ elsif params[:betrag].is_a? Numeric
44
+ params[:betrag] = BigDecimal.new params[:betrag].to_s
30
45
  else
31
- @betrag = -betrag # only store positive amounts
32
- @positiv = false
46
+ raise DTAUSException.new("Betrag is a #{params[:betrag].class}, expected String or Numeric")
33
47
  end
34
- end
35
-
36
-
37
- # 5 Zeichen Art der Transaktion (7a: 2 Zeichen, 7b: 3 Zeichen)
38
- # "04000" Lastschrift des Abbuchungsauftragsverfahren
39
- # "05000" Lastschrift des Einzugsermächtigungsverfahren
40
- # "05005" Lastschrift aus Verfügung im elektronischen Cash-System
41
- # "05006" Wie 05005 mit ausländischen Karten
42
- # "05015" Lastschrift aus Verfügung im elec. Cash-System - POZ
43
- # "51000" Überweisungs-Gutschrift
44
- # "53000" Überweisung Lohn/Gehalt/Rente
45
- # "54XXJ" Vermögenswirksame Leistung (VL) mit Sparzulage
46
- # "56000" Überweisung öffentlicher Kassen
47
- # Die im Textschlüssel mit XX bezeichnete Stelle ist 00 oder der Prozentsatz der Sparzulage.
48
- # Die im Textschlüssel mit J bezeichnete Stelle wird bei Übernahme in eine Zahlung automatisch mit der jeweils aktuellen Jahresendziffer (z.B. 7, wenn 97) ersetzt.
49
- #
50
- def zahlungsart
51
- '05000'
52
- end
53
-
54
- def verwendungszweck_erweiterungen
55
- Erweiterung.from_string(:verwendungszweck, text)
56
- end
57
-
58
- def erweiterungen
59
- @erweiterungen ||= konto.erweiterungen + auftraggeber.erweiterungen + verwendungszweck_erweiterungen
60
- end
61
-
62
- def to_dta
63
- "#{dataC}#{dataC_erweiterungen}"
64
- end
65
48
 
66
- def size
67
- (187 + erweiterungen.size * 29)
68
- end
49
+ # Betrag in Cent
50
+ params[:betrag] = ( params[:betrag] * 100 ).to_i
51
+ if params[:betrag] == 0
52
+ raise DTAUSException.new("Betrag must not be 0.00 €!")
53
+ elsif params[:betrag] > 0
54
+ @betrag = params[:betrag]
55
+ @positiv = true
56
+ else
57
+ @betrag = params[:betrag] * -1
58
+ @positiv = false
59
+ end
69
60
 
70
- private
61
+ @kunden_konto = params[:kunden_konto]
62
+ @transaktionstyp = params[:transaktionstyp]
63
+ @verwendungszweck = Converter.convert_text(params[:verwendungszweck])
71
64
 
72
- # Erstellt den Erweiterungen-Teil des C-Segments für diese Buchung
73
- #
74
- def dataC_erweiterungen
75
- dta = auftraggeber.name[0..26].ljust(27) # 27 Zeichen Name des Auftraggebers
76
- dta += text[0..26].ljust(27) # 27 Zeichen Verwendungszweck
77
- dta += '1' # 1 Zeichen Währungskennzeichen ('1' = Euro)
78
- dta += ' ' # 2 Zeichen Reserviert, 2 Blanks
79
- dta += "%02i" % erweiterungen.size # 2 Zeichen Anzahl der Erweiterungsdatensätze, "00" bis "15"
80
- dta += erweiterungen[0..1].inject('') {|data, erweiterung| data += erweiterung.to_dta}
81
- dta = dta.ljust(128)
82
- if erweiterungen.size > 2
83
- erweiterungen[2..-1].each_slice(4) do |slice|
84
- dta += slice.inject('') {|dta, erweiterung| dta += erweiterung.to_dta}.ljust(128)
85
- end
65
+ if erweiterungen.size > 15
66
+ raise IncorrectSizeException.new("Zuviele Erweiterungen: #{erweiterungen.size}, maximal 15. Verwendungszweck zu lang?")
86
67
  end
87
- raise IncorrectSize.new("Erweiterungen: #{dta.size} Zeichen") if dta.size > 256 * 3 or dta.size % 128 != 0
88
- return dta
89
68
 
90
69
  end
91
70
 
92
- # Erstellt ein C-Segments für diese Buchung
71
+ # Alle Erweiterungen der Buchung, bestehend aus
72
+ # * Inhaber Kundenkonto
73
+ # * Verwendungszweck dieser Buchung
93
74
  #
94
- def dataC
95
- dta = '%04i' % size # 4 Zeichen Länge des Datensatzes, 187 + x * 29 (x..Anzahl Erweiterungsteile)
96
- dta += 'C' # 1 Zeichen Datensatz-Typ, immer 'C'
97
- dta += '%08i' % 0 # 8 Zeichen Bankleitzahl des Auftraggebers (optional)
98
- dta += '%08i' % konto.blz # 8 Zeichen Bankleitzahl des Kunden
99
- dta += '%010i' % konto.nummer # 10 Zeichen Kontonummer des Kunden
100
- dta += '0%011i0' % konto.kunnr # 13 Zeichen Verschiedenes 1. Zeichen: "0" 2. - 12. Zeichen: interne Kundennummer oder Nullen 13. Zeichen: "0"
101
- dta += zahlungsart # 5 Zeichen Art der Transaktion (7a: 2 Zeichen, 7b: 3 Zeichen)
102
- dta += ' ' # 1 Zeichen Reserviert, " " (Blank)
103
- dta += '0' * 11 # 11 Zeichen Betrag
104
- dta += '%08i' % auftraggeber.blz # 8 Zeichen Bankleitzahl des Auftraggebers
105
- dta += '%010i' % auftraggeber.nummer # 10 Zeichen Kontonummer des Auftraggebers
106
- dta += '%011i' % betrag # 11 Zeichen Betrag in Euro einschließlich Nachkommastellen, nur belegt, wenn Euro als Währung angegeben wurde
107
- dta += ' ' * 3 # 3 Zeichen Reserviert, 3 Blanks
108
- dta += konto.name[0..26].ljust(27) # 27 Zeichen Name des Kunden
109
- dta += ' ' * 8 # 8 Zeichen Reserviert, 8 Blanks
110
- raise IncorrectSize.new("C-Segement 1: #{dta.size} Zeichen, 128 erwartet (#{konto.name})") if dta.size != 128
111
- return dta
75
+ # Die Erweiterung für das auftraggeber_konto werden hier nicht aufgeführt!
76
+ def erweiterungen
77
+ kunden_konto.erweiterungen +
78
+ Erweiterung.from_string(:verwendungszweck, verwendungszweck)
112
79
  end
113
80
 
114
81
  end
115
82
  end
116
-
@@ -0,0 +1,36 @@
1
+ # encoding: utf-8
2
+
3
+ module DTAUS
4
+
5
+ # Utility class for converting strings and numbers to DTA-conform representations
6
+ class Converter
7
+
8
+ # Zeichen umsetzen gemäss DTA-Norm
9
+ #
10
+ def self.convert_text(_text)
11
+ tmp = _text.to_s.dup
12
+ tmp = tmp.upcase()
13
+ tmp = tmp.gsub('Ä', 'AE')
14
+ tmp = tmp.gsub('Ü', 'UE')
15
+ tmp = tmp.gsub('Ö', 'OE')
16
+ tmp = tmp.gsub('ä', 'AE')
17
+ tmp = tmp.gsub('ü', 'UE')
18
+ tmp = tmp.gsub('ö', 'OE')
19
+ tmp = tmp.gsub('ß', 'SS')
20
+ tmp = tmp.strip
21
+ end
22
+
23
+ # Konvertiert einen String in einen Integer
24
+ # indem alle Nicht-Digits entfernt werden.
25
+ # Lässt Integer unberührt.
26
+ #
27
+ def self.convert_number(_number)
28
+ case _number
29
+ when Integer then _number
30
+ when String then _number.strip.gsub(/\D/, '').to_i
31
+ else raise DTAUSException.new("Cannot convert #{_number.class} to Integer")
32
+ end
33
+ end
34
+
35
+ end
36
+ end
@@ -0,0 +1,77 @@
1
+ # encoding: utf-8
2
+
3
+ module DTAUS
4
+
5
+ # Vollständiger DTA-Datensatz mit Header (A), Body (C) und Footer (E)
6
+ class Datensatz
7
+
8
+ attr_reader :auftraggeber_konto, :buchungen, :ausfuehrungsdatum, :positiv, :transaktionstyp
9
+ alias :positiv? :positiv
10
+
11
+ # Vollständigen DTA-Datensatz erstellen
12
+ #
13
+ # Parameter:
14
+ # [<tt>_transaktionstyp</tt>] Art der Transaktionen (als :Symbol)
15
+ # * <tt>:lastschrift</tt> für Lastschriften Kundenseitig
16
+ # * <tt>:gutschrift</tt> für Gutschriften Kundenseitig
17
+ # [<tt>_auftraggeber_konto</tt>] das DTAUS::Konto des Auftraggebers
18
+ # [<tt>_ausfuehrungsdatum</tt>] Ausführungsdatum des Datensatzes,
19
+ # _optional_, Default-Wert ist die aktuelle Zeit
20
+ #
21
+ def initialize(_transaktionstyp, _auftraggeber_konto, _ausfuehrungsdatum = Time.now)
22
+ unless [:lastschrift, :gutschrift].include?(_transaktionstyp)
23
+ raise DTAUSException.new("Transaktionstyp has to be one of [:lastschrift, :gutschrift]")
24
+ end
25
+ unless _auftraggeber_konto.is_a?(Konto)
26
+ raise DTAUSException.new("Konto expected, got #{_auftraggeber_konto.class}")
27
+ end
28
+ unless _ausfuehrungsdatum.is_a?(Date) or _ausfuehrungsdatum.is_a?(Time)
29
+ raise DTAUSException.new("Date or Time expected, got #{_ausfuehrungsdatum.class}")
30
+ end
31
+
32
+ @transaktionstyp = _transaktionstyp
33
+ @auftraggeber_konto = _auftraggeber_konto
34
+ @ausfuehrungsdatum = _ausfuehrungsdatum
35
+ @buchungen = []
36
+ end
37
+
38
+ # Eine Buchung zum Datensatz hinzufügen.
39
+ #
40
+ # Es wird geprüft, ob das Vorzeichen identisch mit den bisherigen Vorzeichen ist.
41
+ #
42
+ def add(_buchung)
43
+ raise DTAUSException.new("Buchung expected, got #{_buchung.class}") unless _buchung.is_a?(Buchung)
44
+
45
+ # Die erste Buchung bestimmt, ob alle Beträge positiv oder negativ sind.
46
+ @positiv = _buchung.positiv? if @buchungen.empty?
47
+
48
+ # Wirf Exception wenn Vorzeichen gemischt werden
49
+ unless @positiv == _buchung.positiv?
50
+ raise DTAUSException.new("Nicht erlaubter Vorzeichenwechsel! "+
51
+ "Buchung muss wie die vorherigen Buchungen #{positiv? ? 'positiv' : 'negativ'} sein!")
52
+ end
53
+
54
+ @buchungen << _buchung
55
+ end
56
+
57
+ # DTA-Repräsentation dieses Datensatzes
58
+ #
59
+ def to_dta
60
+ DtaGenerator.new(self).to_dta
61
+ end
62
+ alias :to_s :to_dta
63
+
64
+ # Schreibt die DTAUS-Datei
65
+ #
66
+ # Parameter:
67
+ # [<tt>filename</tt>] Name der zu schreibenden Datei; _optional_, Default-Wert ist <tt>DTAUS0.TXT</tt>
68
+ #
69
+ def to_file(filename = 'DTAUS0.TXT')
70
+ File.open(filename, 'w') do |file|
71
+ file << to_dta
72
+ end
73
+ end
74
+
75
+ end
76
+
77
+ end