dtaus 0.1.1 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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