king_dtaus 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,4 @@
1
+ nbproject/*
2
+ coverage/*
3
+ rdoc/*
4
+ pkg/*
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2010 [Georg Leciejewski SalesKing GmbH]
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.rdoc ADDED
@@ -0,0 +1,32 @@
1
+ = Dtaus
2
+
3
+ DTAUS is a format for german bank transfers and is short for
4
+ "Datenträgeraustausch". The format itself totally sucks because it was
5
+ established in the last century, to be used on floppy disks. Still almost
6
+ all german banks use it(they only seem innovative at robbing), and it is
7
+ therefore supported in common banking programs too.
8
+
9
+ This gem saves you all the trouble when generating dtaus-text.
10
+
11
+ == Install
12
+
13
+ gem install king_dtaus
14
+
15
+ == Features
16
+
17
+
18
+
19
+ == Example
20
+
21
+ TODO - read the specs
22
+
23
+
24
+ == Credits
25
+
26
+ This gem used https://rubygems.org/gems/DTAUS as a starting point.
27
+ It was disected, turned into a real class structure, bugs where fixed and
28
+ of course a full test suite ensures its functionality.
29
+
30
+ Copyright (c) 2009-2010 Georg Leciejewski,
31
+ Bugfixes and enhancements by Georg Ledermann
32
+ released under the MIT license
data/Rakefile ADDED
@@ -0,0 +1,46 @@
1
+ require 'rake'
2
+ require 'rake/rdoctask'
3
+ require 'spec/rake/spectask'
4
+
5
+ desc 'Default: run specs.'
6
+ task :default => :spec
7
+
8
+ spec_files = Rake::FileList["spec/**/*_spec.rb"]
9
+
10
+ desc "Run specs"
11
+ Spec::Rake::SpecTask.new do |t|
12
+ t.spec_files = spec_files
13
+ t.spec_opts = ["-c"]
14
+ end
15
+
16
+ desc "Generate code coverage"
17
+ Spec::Rake::SpecTask.new(:coverage) do |t|
18
+ t.spec_files = spec_files
19
+ t.rcov = true
20
+ t.rcov_opts = ['--exclude', 'spec,/var/lib/gems']
21
+ end
22
+
23
+ desc 'Generate documentation'
24
+ Rake::RDocTask.new(:rdoc) do |rdoc|
25
+ rdoc.rdoc_dir = 'rdoc'
26
+ rdoc.title = 'dtaus'
27
+ rdoc.options << '--line-numbers' << '--inline-source'
28
+ rdoc.rdoc_files.include('README')
29
+ rdoc.rdoc_files.include('lib/**/*.rb')
30
+ end
31
+
32
+ begin
33
+ require 'jeweler'
34
+ Jeweler::Tasks.new do |gem|
35
+ gem.name = "king_dtaus"
36
+ gem.summary = %Q{Generate DTAUS strings and files}
37
+ gem.description = %Q{DTAUS is a text-based format, to create bank transfers for german banks. This gem helps with the creation of those transfer files.}
38
+ gem.email = "gl@salesking.eu"
39
+ gem.homepage = "http://github.com/salesking/king_dtaus"
40
+ gem.authors = ["Georg Leciejewski", "Georg Ledermann"]
41
+ # gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
42
+ end
43
+ Jeweler::GemcutterTasks.new
44
+ rescue LoadError
45
+ puts "Jeweler (or a dependency) not available. Install it with: gem install jeweler"
46
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 1.0.0
data/init.rb ADDED
@@ -0,0 +1 @@
1
+ require "#{File.dirname(__FILE__)}/lib/king_dtaus"
@@ -0,0 +1,18 @@
1
+ module KingDta
2
+ #Kontodaten verwalten mit Name des Inhabers und Bank, Bankleitzahl und Kontonummer.
3
+ class Account
4
+ include KingDta::Helper
5
+ # dta~ jeweilige Feld in DTAUS-Norm
6
+ attr_reader :bank_account_number, :bank_number, :owner, :kunnr, :dtakunnr
7
+ def initialize( ban, bank_number, owner, kunnr="" )
8
+ @bank_account_number = ban.kind_of?( Integer ) ? ban : ban.gsub(/\s/, '').to_i
9
+ @bank_number = bank_number.kind_of?( Integer ) ? bank_number : bank_number.gsub(/\s/, '').to_i
10
+ @owner= convert_text( owner )
11
+ @kunnr = kunnr.gsub(/\s/, '').to_i
12
+ raise "Invalid bank account number #{ban}" if @bank_account_number == 0
13
+ raise "BLZnummer #{bank_number} ungültig" if @bank_number == 0
14
+ raise "Invalid account owner #{owner}" unless @owner.kind_of?(String)
15
+ # @dtakunnr = convert_text( @kunnr )
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,47 @@
1
+ module KingDta
2
+ class Booking
3
+ include KingDta::Helper
4
+
5
+ # Die am häufigsten benötigten Textschlüssel
6
+ LASTSCHRIFT_ABBUCHUNG = '04000'
7
+ LASTSCHRIFT_EINZUGSERMAECHTIGUNG = '05000'
8
+ UEBERWEISUNG_GUTSCHRIFT = '51000'
9
+
10
+ attr_reader :value, :account, :text, :schluessel
11
+ #Eine Buchung ist definiert durch:
12
+ #- Konto (siehe Klasse Konto
13
+ #- Betrag
14
+ # Der Betrag kann , oder . als Dezimaltrenner enthalten.
15
+ #- optional Buchungstext
16
+ def initialize( account, value, text=nil, schluessel=nil )
17
+ raise "Hey, a booking should have an Account" unless account.kind_of?( Account )
18
+ @account = account
19
+ @text = text ? convert_text( text ) : text
20
+ @schluessel = schluessel
21
+ if value.is_a?(String)
22
+ value = BigDecimal.new value.sub(',', '.')
23
+ elsif value.is_a?(Numeric)
24
+ value = BigDecimal.new value.to_s
25
+ else
26
+ raise "Übergabefehler: Betrag ist kein String/Numeric"
27
+ end
28
+ value = ( value * 100 ).to_i #€-Cent
29
+ if value == 0
30
+ raise "Booking Value is 0"
31
+ elsif value > 0
32
+ @value = value
33
+ @pos = true
34
+ else
35
+ @value = - value
36
+ @pos = false
37
+ end
38
+ end
39
+
40
+ def text=(text)
41
+ @text = convert_text( text )
42
+ end
43
+
44
+ def pos?; @pos end
45
+
46
+ end #class Buchung
47
+ end #module dtaus
@@ -0,0 +1,308 @@
1
+ #Erstelle eine DTAUS-Datei.
2
+ #Typ ist 'LK' (Lastschrift Kunde) oder 'GK' (Gutschrift Kunde)
3
+ #
4
+ #Infos zu DTAUS: http://www.infodrom.org/projects/dtaus/dtaus.php3
5
+ #
6
+ #Die Methoden müssen in der Reihenfolge:
7
+ #- account (definieren des eigenen Kontos)
8
+ #- bookings
9
+ #- dtaDatei/begleitblatt
10
+ #abgearbeitet werden.
11
+ #
12
+ #Kontodaten verwalten mit Name des Inhabers und Bank, Bankleitzahl und Kontonummer.
13
+ module KingDta
14
+ class Dtaus
15
+ include KingDta::Helper
16
+ attr_reader :sum_bank_account_numbers, :sum_bank_numbers, :sumBetrag, :default_text
17
+
18
+ #Zieldatei und Datum der Datei werden definiert
19
+ # ==== Parameter
20
+ def initialize( typ, datum=Date.today )
21
+ raise "Wrong date format. Make it a Time or Date object with yyyy-mm-dd" unless datum.respond_to?(:strftime)
22
+ raise "Unknown order type: #{typ}. Allowed Values are LK, GK" unless ['LK','GK'].include?(typ)
23
+ @datum = datum
24
+ @typ = typ
25
+ @value_pos = true #alle Beträge sind positiv. Variable wird mit erstem Eintrag geändert
26
+ @closed = false
27
+ @default_text = '' # default verwendungzweck
28
+ end
29
+
30
+ # Übergabe der eigenen Kontodaten als Objekt der Klasse Konto
31
+ def account=( account )
32
+ raise "Come on i need an Account object" unless account.kind_of?( Account )
33
+ @account = account
34
+ end
35
+
36
+ # The dtaus format as string. all data is appended to it during creation
37
+ def dta_string
38
+ @dta_string ||= ''
39
+ end
40
+ def bookings
41
+ @bookings ||= []
42
+ end
43
+ # default text used on all bookings with emtpy text
44
+ def default_text=(text='')
45
+ @default_text = convert_text( text )
46
+ end
47
+
48
+ #Eine Buchung hinzufügen. Es wird geprüft, ob das Vorzeichen identisch mit den bisherigen Vorzeichen ist.
49
+ def add ( booking )
50
+ raise "The file has alreay been closed, cannot add new booking" if @closed
51
+ #Die erste Buchung bestimmt, ob alle Beträge positiv oder negativ sind.
52
+ #alle Beträge sind positiv. Variable wird mit erstem Eintrag geändert
53
+ @value_pos = booking.pos? if bookings.empty? == []
54
+ raise "The prefix within bookings changed from #{@value_pos} to #{booking.pos?}" if @value_pos != booking.pos?
55
+ bookings << booking
56
+ end
57
+
58
+ # Creates the whole dta string(in the right order) and returns it
59
+ def create
60
+ raise "Cannot create DTAUS without bookings" if bookings.empty?
61
+ @closed = true
62
+ # cleanup before we start
63
+ @dta_string = dta_string.empty? ? dta_string : ''
64
+ set_checksums
65
+ add_a
66
+ bookings.each{ |b| add_c( b) }
67
+ add_e
68
+ dta_string
69
+ end
70
+
71
+ def set_checksums
72
+ @sum_bank_account_numbers, @sum_bank_numbers, @sumBetrag = 0,0,0
73
+ bookings.each do |b|
74
+ @sum_bank_account_numbers += b.account.bank_account_number
75
+ @sum_bank_numbers += b.account.bank_number
76
+ @sumBetrag+= b.value
77
+ end
78
+ end
79
+
80
+ #Create a DTA-File
81
+ def create_file(filename ='DTAUS0.TXT')
82
+ file = open( filename, 'w')
83
+ file << create
84
+ file.close()
85
+ print "#{filename} erstellt , #{@bookings.size} Einträge\n"
86
+ end
87
+
88
+
89
+ #Erstellen A-Segment der DTAUS-Datei
90
+ #Aufbau des Segments:
91
+ # Nr. Start Länge Beschreibung
92
+ # 1 0 4 Zeichen Länge des Datensatzes, immer 128 Bytes, also immer "0128"
93
+ # 2 4 1 Zeichen Datensatz-Typ, immer 'A'
94
+ # 3 5 2 Zeichen Art der Transaktionen
95
+ # "LB" für Lastschriften Bankseitig
96
+ # "LK" für Lastschriften Kundenseitig
97
+ # "GB" für Gutschriften Bankseitig
98
+ # "GK" für Gutschriften Kundenseitig
99
+ # 4 7 8 Zeichen Bankleitzahl des Auftraggebers
100
+ # 5 15 8 Zeichen CST, "00000000", nur belegt, wenn Diskettenabsender Kreditinstitut
101
+ # 6 23 27 Zeichen Name des Auftraggebers
102
+ # 7 50 6 Zeichen aktuelles Datum im Format DDMMJJ
103
+ # 8 56 4 Zeichen CST, " " (Blanks)
104
+ # 9 60 10 Zeichen Kontonummer des Auftraggebers
105
+ # 10 70 10 Zeichen Optionale Referenznummer
106
+ # 11a 80 15 Zeichen Reserviert, 15 Blanks
107
+ # 11b 95 8 Zeichen Ausführungsdatum im Format DDMMJJJJ. Nicht jünger als Erstellungsdatum (A7), jedoch höchstens 15 Kalendertage später. Sonst Blanks.
108
+ # 11c 103 24 Zeichen Reserviert, 24 Blanks
109
+ # 12 127 1 Zeichen Währungskennzeichen
110
+ # " " = DM
111
+ # "1" = Euro
112
+ # Insgesamt 128 Zeichen
113
+ def add_a
114
+ data = '0128'
115
+ data += 'A' #Segment
116
+ data += @typ #Lastschriften Kunde
117
+ data += '%8i' % @account.bank_number #.rjust(8) #bank_number
118
+ data += '%08i' % 0 #belegt, wenn Bank
119
+ data += '%-27.27s' % @account.owner
120
+ data += @datum.strftime("%d%m%y") #aktuelles Datum im Format DDMMJJ
121
+ data += ' ' * 4 #bankinternes Feld
122
+ data += '%010i' % @account.bank_account_number
123
+ data += '%010i' % 0 #Referenznummer
124
+ data += ' ' * 15 #Reserve
125
+ data += '%8s' % @datum.strftime("%d%m%Y") #Ausführungsdatum (ja hier 8 Stellen, Erzeugungsdat. hat 6 Stellen)
126
+ data += ' ' * 24 #Reserve
127
+ data += '1' #Kennzeichen Euro
128
+ raise "DTAUS: Längenfehler A (#{data.size} <> 128)\n" if data.size != 128
129
+ dta_string << data
130
+ end #dataA
131
+
132
+ #Erstellen C-Segmente (Buchungen mit Texten) der DTAUS-Datei
133
+ #Aufbau:
134
+ # Nr. St Länge Beschreibung
135
+ # 1 0 4 Zeichen Länge des Datensatzes, 187 + x * 29 (x..Anzahl Erweiterungsteile)
136
+ # 2 4 1 Zeichen Datensatz-Typ, immer 'C'
137
+ # 3 5 8 Zeichen Bankleitzahl des Auftraggebers (optional)
138
+ # 4 13 8 Zeichen Bankleitzahl des Kunden
139
+ # 5 21 10 Zeichen Kontonummer des Kunden
140
+ # 6 31 13 Zeichen Verschiedenes
141
+ # 1. Zeichen: "0"
142
+ # 2. - 12. Zeichen: interne Kundennummer oder Nullen
143
+ # 13. Zeichen: "0"
144
+ # Die interne Nummer wird vom erstbeauftragten Institut zum endbegünstigten Institut weitergeleitet. Die Weitergabe der internenen Nummer an den Überweisungsempfänger ist der Zahlstelle freigestellt.
145
+ # 7 44 5 Zeichen Art der Transaktion (7a: 2 Zeichen, 7b: 3 Zeichen)
146
+ # "04000" Lastschrift des Abbuchungsauftragsverfahren
147
+ # "05000" Lastschrift des Einzugsermächtigungsverfahren
148
+ # "05005" Lastschrift aus Verfügung im elektronischen Cash-System
149
+ # "05006" Wie 05005 mit ausländischen Karten
150
+ # "51000" Überweisungs-Gutschrift
151
+ # "53000" Überweisung Lohn/Gehalt/Rente
152
+ # "5400J" Vermögenswirksame Leistung (VL) ohne Sparzulage
153
+ # "5400J" Vermögenswirksame Leistung (VL) mit Sparzulage
154
+ # "56000" Überweisung öffentlicher Kassen
155
+ # Die im Textschlüssel mit J bezeichnete Stelle, wird bei Übernahme in eine Zahlung automatisch mit der jeweils aktuellen Jahresendziffer (7, wenn 97) ersetzt.
156
+ # 8 49 1 Zeichen Reserviert, " " (Blank)
157
+ # 9 50 11 Zeichen Betrag in DM
158
+ # 10 61 8 Zeichen Bankleitzahl des Auftraggebers
159
+ # 11 69 10 Zeichen Kontonummer des Auftraggebers
160
+ # 12 79 11 Zeichen Betrag in Euro einschließlich Nachkommastellen, nur belegt, wenn Euro als Währung angegeben wurde (A12, C17a), sonst Nullen
161
+ # 13 90 3 Zeichen Reserviert, 3 Blanks
162
+ # 14a 93 27 Zeichen Name des Kunden
163
+ # 14b 120 8 Zeichen Reserviert, 8 Blanks
164
+ # Insgesamt 128 Zeichen
165
+ #
166
+ # 15 128 27 Zeichen Name des Auftraggebers
167
+ # 16 155 27 Zeichen Verwendungszweck
168
+ # 17a 182 1 Zeichen Währungskennzeichen
169
+ # " " = DM
170
+ # "1" = Euro
171
+ # 17b 183 2 Zeichen Reserviert, 2 Blanks
172
+ # 18 185 2 Zeichen Anzahl der Erweiterungsdatensätze, "00" bis "15"
173
+ # 19 187 2 Zeichen Typ (1. Erweiterungsdatensatz)
174
+ # "01" Name des Kunden
175
+ # "02" Verwendungszweck
176
+ # "03" Name des Auftraggebers
177
+ # 20 189 27 Zeichen Beschreibung gemäß Typ
178
+ # 21 216 2 Zeichen wie C19, oder Blanks (2. Erweiterungsdatensatz)
179
+ # 22 218 27 Zeichen wie C20, oder Blanks
180
+ # 23 245 11 Zeichen 11 Blanks
181
+ # Insgesamt 256 Zeichen, kann wiederholt werden (max 3 mal)
182
+ # ==== Parameter
183
+ # booking<Object>::Booking object to be written to c-sektion
184
+ # ==== Returns
185
+ # <String>:: The current dta_string
186
+ def add_c( booking)
187
+ zahlungsart = if @typ == 'LK'
188
+ booking.schluessel || Booking::LASTSCHRIFT_EINZUGSERMAECHTIGUNG
189
+ elsif @typ == 'GK'
190
+ booking.schluessel || Booking::UEBERWEISUNG_GUTSCHRIFT
191
+ else
192
+ raise 'Wrong booking type'
193
+ end
194
+ #Extended segments Long name & booking texts
195
+ exts = [] #('xx', 'inhalt') xx: 01=Name 02=Verwendung 03=Name
196
+ # 1. Satzabschnitt
197
+ #data1 = '%4i' % ?? #Satzlänge kommt später
198
+ data1 = 'C'
199
+ data1 += '%08i' % 0 #freigestellt
200
+ data1 += '%08i' % booking.account.bank_number
201
+ data1 += '%010i' % booking.account.bank_account_number
202
+ data1 += '0%011i0' % booking.account.kunnr #interne Kundennummer
203
+ data1 += zahlungsart
204
+ data1 += ' ' #bankintern
205
+ data1 += '0' * 11 #Reserve
206
+ data1 += '%08i' % @account.bank_number
207
+ data1 += '%010i' % @account.bank_account_number
208
+ data1 += '%011i' % booking.value #Betrag in Euro einschl. Nachkomma
209
+ data1 += ' ' * 3
210
+ data1 += '%-27.27s' % booking.account.owner #Name Begünstigter/Zahlungspflichtiger
211
+ exts << ['01', booking.account.owner[27..999] ] if booking.account.owner.size > 27
212
+ data1 += ' ' * 8
213
+ #Einfügen erst möglich, wenn Satzlänge bekannt
214
+
215
+ # 2. Satzabschnitt
216
+ data2 = "%27.27s" % @account.owner
217
+ zweck = booking.text || default_text
218
+ #Erste 27 Zeichen
219
+ #Wenn text < 26 Zeichen, dann mit spaces auffüllen.
220
+ data2 += zweck[0..26].ljust(27)
221
+ zweck = zweck[27..999]
222
+ # cur text into 27 long pieces
223
+ while zweck && zweck.size > 0 && exts.size < 13
224
+ exts << ['02', zweck.ljust(27) ]
225
+ zweck = zweck[27..999]
226
+ end
227
+ exts << ['03', @account.owner[27..999] ] if @account.owner.size > 27
228
+
229
+ data2 += '1' #Währungskennzeichen
230
+ data2 += ' ' * 2
231
+ # Gesamte Satzlänge ermitteln ( data1(+4) + data2 + Erweiterungen )
232
+ data1 = "%04i#{data1}" % ( data1.size + 4 + data2.size+ 2 + exts.size * 29 )
233
+ raise "DTAUS: Längenfehler C/1 #{data1.size}, #{booking.account.name}" unless data1.size == 128
234
+ dta_string << data1
235
+ #Anzahl Erweiterungen anfügen
236
+ data2 += '%02i' % exts.size #Anzahl Erweiterungsteile
237
+ #Die ersten zwei Erweiterungen gehen in data2,
238
+ #Satz 3/4/5 à 4 Erweiterungen -> max. 14 Erweiterungen (ich ignoriere möglichen Satz 6)
239
+ exts += [ ['00', "" ] ] * (14 - exts.size)
240
+ #Die ersten zwei Erweiterungen gehen in data2, wenn leer nur mit blanks als füllung
241
+ exts[0..1].each{|e| data2 += "%2.2s%-27.27s" % format_ext(e[0], e[1]) }
242
+ data2 += ' ' * 11
243
+ # add the final piece of the second C section
244
+ raise "DTAUS: Längenfehler C/2 #{data2.size}, #{booking.account.name}" if data2.size != 128
245
+ dta_string << data2
246
+ #Erstellen der Texterweiterungen à vier Stück
247
+ add_ext( exts[2..5] )
248
+ add_ext( exts[6..9] )
249
+ add_ext( exts[10..13] )
250
+ dta_string
251
+ end #dataC
252
+
253
+ # Format an extension so it can be used in string substitution
254
+ # ==== Returns
255
+ # Array[String, String]::[Extesnsion type(01 02 03), 'text content ..']
256
+ def format_ext(type, content)
257
+ ext = ( type == '00' ) ? [' ', ' '] : [ type, convert_text(content) ]
258
+ ext
259
+ end
260
+
261
+ # Add a section-C extension, always containing the section type followed by
262
+ # 4 segments with 27 chars and an ending seperator of 12 blanks
263
+ # Only adds the segement if something is in there
264
+ # ==== Parameter
265
+ # <Array[Array[String,String]]>:: two dim. ary containing: [extension type(01 02 03),string content]
266
+ def add_ext( ext)
267
+ raise "Nur #{ext.size} Erweiterungstexte, 4 benötigt" if ext.size != 4
268
+ str = "%2.2s%-27.27s" % format_ext(ext[0][0], ext[0][1] )
269
+ str += "%2.2s%-27.27s" % format_ext( ext[1][0], ext[1][1] )
270
+ str += "%2.2s%-27.27s" % format_ext( ext[2][0], ext[2][1] )
271
+ str += "%2.2s%-27.27s" % format_ext( ext[3][0], ext[3][1] )
272
+ # Trennzeichen 12 blanks
273
+ str += ' ' * 12
274
+ unless str !~ /\S/ # only add if something is in there .. only whitespace => same as str.blank?
275
+ raise "DTAUS: Längenfehler C/3 #{str.size} " if str.size != 128
276
+ dta_string << str
277
+ end
278
+ end #dataC
279
+
280
+ #Erstellen E-Segment (Prüfsummen) der DTAUS-Datei
281
+ #Aufbau:
282
+ # Nr. Start Länge Beschreibung
283
+ # 1 0 4 Zeichen Länge des Datensatzes, immer 128 Bytes, also immer "0128"
284
+ # 2 4 1 Zeichen Datensatz-Typ, immer 'E'
285
+ # 3 5 5 Zeichen " " (Blanks)
286
+ # 4 10 7 Zeichen Anzahl der Datensätze vom Typ C
287
+ # 5 17 13 Zeichen Kontrollsumme Beträge
288
+ # 6 30 17 Zeichen Kontrollsumme Kontonummern
289
+ # 7 47 17 Zeichen Kontrollsumme Bankleitzahlen
290
+ # 8 64 13 Zeichen Kontrollsumme Euro, nur belegt, wenn Euro als Währung angegeben wurde (A12, C17a)
291
+ # 9 77 51 Zeichen 51 Blanks
292
+ # Insgesamt 128 Zeichen
293
+ def add_e
294
+ str = '0128'
295
+ str += 'E'
296
+ str += ' ' * 5
297
+ str += '%07i' % @bookings.size
298
+ str += '0' * 13 #Reserve
299
+ str += '%017i' % @sum_bank_account_numbers
300
+ str += '%017i' % @sum_bank_numbers
301
+ str += '%013i' % @sumBetrag
302
+ str += ' ' * 51 #Abgrenzung Datensatz
303
+ raise "DTAUS: Längenfehler E #{str.size} <> 128" if str.size != 128
304
+ dta_string << str
305
+ end
306
+ # private :dataA, :dataC, :dataE
307
+ end #class dtaus
308
+ end
@@ -0,0 +1,33 @@
1
+ module KingDta
2
+ module Helper
3
+ #Zeichen umsetzen gemäss DTA-Norm
4
+ def convert_text( text)
5
+ text = text.to_s
6
+ return text if text.empty?
7
+ raise "Text kein String >#{text}< (#{text.class})" unless text.kind_of?( String )
8
+ text.gsub!('Ä', 'AE')
9
+ text.gsub!('Ü', 'UE')
10
+ text.gsub!('Ö', 'OE')
11
+ text.gsub!('ä', 'AE')
12
+ text.gsub!('ü', 'UE')
13
+ text.gsub!('ö', 'OE')
14
+ text.gsub!('ß', 'SS')
15
+
16
+ text.gsub! /[^a-zA-Z0-9\ \.\,\&\-\/\+\*\$\%]/, '' # Remove all invalid chars
17
+
18
+ text = text.upcase.strip
19
+ text
20
+ # text = text.to_s()
21
+ # puts "Text kein String >#{text}< (#{text.class})" if ! text.kind_of?( String )
22
+ # text = text.upcase()
23
+ # text = text.gsub('Ä', 'AE')
24
+ # text = text.gsub('Ü', 'UE')
25
+ # text = text.gsub('Ö', 'OE')
26
+ # text = text.gsub('ä', 'AE')
27
+ # text = text.gsub('ü', 'UE')
28
+ # text = text.gsub('ö', 'OE')
29
+ # text = text.gsub('ß', 'SS')
30
+ # return text = text.strip
31
+ end
32
+ end
33
+ end
data/lib/king_dtaus.rb ADDED
@@ -0,0 +1,5 @@
1
+ require "bigdecimal"
2
+ require "#{File.dirname(__FILE__)}/king_dta/helper"
3
+ require "#{File.dirname(__FILE__)}/king_dta/account"
4
+ require "#{File.dirname(__FILE__)}/king_dta/booking"
5
+ require "#{File.dirname(__FILE__)}/king_dta/dtaus"
@@ -0,0 +1,20 @@
1
+ require "#{File.dirname(__FILE__)}/spec_helper"
2
+
3
+ describe KingDta::Booking do
4
+
5
+ before :each do
6
+ kto1 = test_kto1
7
+ kto2 = test_kto2
8
+ @account = KingDta::Account.new( kto2.nr, kto2.blz, kto2.name, kto2.bank )
9
+ end
10
+
11
+ it "should have no rounding error for string" do
12
+ booking = KingDta::Booking.new(@account, "159.73")
13
+ booking.value.should == 15973
14
+ end
15
+
16
+ it "should have no rounding error for float" do
17
+ booking = KingDta::Booking.new(@account, 159.73)
18
+ booking.value.should == 15973
19
+ end
20
+ end
@@ -0,0 +1,106 @@
1
+ require "#{File.dirname(__FILE__)}/spec_helper"
2
+
3
+ # All Test DTA output strings are validated with sFirm => lokal Sparkassen Software
4
+ describe KingDta::Dtaus do
5
+
6
+ before :each do
7
+ @dtaus = KingDta::Dtaus.new('LK', Date.today)
8
+ @kto1 = test_kto1
9
+ @kto2 = test_kto2
10
+ @dtaus.account = KingDta::Account.new( @kto1.nr, @kto1.blz, @kto1.name, @kto1.bank )
11
+ @booking = KingDta::Booking.new(
12
+ KingDta::Account.new( @kto2.nr, @kto2.blz, @kto2.name, @kto2.bank ),
13
+ 220.25 )
14
+ end
15
+
16
+ it "should not init without values" do
17
+ lambda{ KingDta::Dtaus.new }.should raise_error(ArgumentError)
18
+ end
19
+ it "should init with valid values" do
20
+ lambda{ KingDta::Dtaus.new('LK', Date.today) }.should_not raise_error(ArgumentError)
21
+ end
22
+
23
+ it "should create header" do
24
+ str = @dtaus.add_a
25
+ str.length.should == 128
26
+ out = "0128ALK3704004400000000GIMME YOUR MONEY AG #{Date.today.strftime("%d%m%y")} 00028800370000000000 #{Date.today.strftime("%d%m%Y")} 1"
27
+ str.should == out
28
+ #60-70 kontonummer mit nullen aufgefüllt
29
+ str[60...70].should == "000#{test_kto1.nr}"
30
+ str.should include(test_kto1.blz)
31
+ end
32
+
33
+ it "should create checksums" do
34
+ @dtaus.add(@booking)
35
+ @dtaus.set_checksums
36
+ @dtaus.sum_bank_account_numbers.should == 2787777
37
+ @dtaus.sum_bank_numbers.should == 37040044
38
+ @dtaus.sumBetrag.should == 22025
39
+ end
40
+
41
+ it "should create c-sektion with booking text at 19" do
42
+ @dtaus.add(@booking)
43
+ @dtaus.bookings.first.text = 'SalesKing Monatsbeitrag 08/10 Freelancer Version'
44
+ @dtaus.add_c(@booking)
45
+ str = @dtaus.dta_string
46
+ str.length.should == 256
47
+ str.should include(@kto2.name.upcase)
48
+ out = "0216C00000000370400440002787777000000000000005000 0000000000037040044000288003700000022025 PETER & MAY GMBH GIMME YOUR MONEY AGSALESKING MONATSBEITRAG 08/1 010210 FREELANCER VERSION "
49
+ str.should == out
50
+ end
51
+
52
+ it "should create c-sektion with default booking text" do
53
+ @dtaus.default_text = 'Default verwendungszweck'
54
+ @dtaus.add_c(@booking)
55
+ str = @dtaus.dta_string
56
+ str.length.should == 256
57
+ str.should include(@kto2.name.upcase)
58
+ out = "0187C00000000370400440002787777000000000000005000 0000000000037040044000288003700000022025 PETER & MAY GMBH GIMME YOUR MONEY AGDEFAULT VERWENDUNGSZWECK 1 00 "
59
+ str.should == out
60
+ end
61
+
62
+ it "should create the whole dta string with a single booking" do
63
+ @dtaus.default_text = 'Default verwendungszweck'
64
+ @dtaus.add(@booking)
65
+ str = @dtaus.create
66
+ str.length.should == 512
67
+ str.should include(@kto1.name.upcase)
68
+ str.should include(@kto2.name.upcase)
69
+ str.should include(@dtaus.default_text.upcase)
70
+ out = "0128ALK3704004400000000GIMME YOUR MONEY AG #{Date.today.strftime("%d%m%y")} 00028800370000000000 #{Date.today.strftime("%d%m%Y")} 1"+
71
+ "0187C00000000370400440002787777000000000000005000 0000000000037040044000288003700000022025 PETER & MAY GMBH GIMME YOUR MONEY AGDEFAULT VERWENDUNGSZWECK 1 00 "+
72
+ "0128E 0000001000000000000000000000002787777000000000370400440000000022025 "
73
+ str.should == out
74
+ end
75
+
76
+ it "should create whole dta string with long booking text in extension" do
77
+ @dtaus.add(@booking)
78
+ @dtaus.bookings.first.text = 'Rgn R-3456-0102220 Monatsbeitrag 08/10 Freelancer Version Vielen Dank Ihre SalesKing GmbH'
79
+ str = @dtaus.create
80
+ str.length.should == 640
81
+ str.should include(@kto2.name.upcase)
82
+ out = "0128ALK3704004400000000GIMME YOUR MONEY AG #{Date.today.strftime("%d%m%y")} 00028800370000000000 #{Date.today.strftime("%d%m%Y")} 1"+
83
+ "0274C00000000370400440002787777000000000000005000 0000000000037040044000288003700000022025 PETER & MAY GMBH GIMME YOUR MONEY AGRGN R-3456-0102220 MONATSBE1 0302ITRAG 08/10 FREELANCER VERS02ION VIELEN DANK IHRE SALESK 02ING GMBH "+
84
+ "0128E 0000001000000000000000000000002787777000000000370400440000000022025 "
85
+ str.should == out
86
+ end
87
+
88
+ it "should create the whole dta string with a lot of bookings" do
89
+ @dtaus.default_text = 'Default Verwendungszweck'
90
+ 6.times { @dtaus.add(@booking) }
91
+ str = @dtaus.create
92
+ str.length.should == 1792
93
+ str.should include(@kto1.name.upcase)
94
+ str.should include(@kto2.name.upcase)
95
+ str.should include(@dtaus.default_text.upcase)
96
+ out = "0128ALK3704004400000000GIMME YOUR MONEY AG #{Date.today.strftime("%d%m%y")} 00028800370000000000 #{Date.today.strftime("%d%m%Y")} 1"+
97
+ "0187C00000000370400440002787777000000000000005000 0000000000037040044000288003700000022025 PETER & MAY GMBH GIMME YOUR MONEY AGDEFAULT VERWENDUNGSZWECK 1 00 "+
98
+ "0187C00000000370400440002787777000000000000005000 0000000000037040044000288003700000022025 PETER & MAY GMBH GIMME YOUR MONEY AGDEFAULT VERWENDUNGSZWECK 1 00 "+
99
+ "0187C00000000370400440002787777000000000000005000 0000000000037040044000288003700000022025 PETER & MAY GMBH GIMME YOUR MONEY AGDEFAULT VERWENDUNGSZWECK 1 00 "+
100
+ "0187C00000000370400440002787777000000000000005000 0000000000037040044000288003700000022025 PETER & MAY GMBH GIMME YOUR MONEY AGDEFAULT VERWENDUNGSZWECK 1 00 "+
101
+ "0187C00000000370400440002787777000000000000005000 0000000000037040044000288003700000022025 PETER & MAY GMBH GIMME YOUR MONEY AGDEFAULT VERWENDUNGSZWECK 1 00 "+
102
+ "0187C00000000370400440002787777000000000000005000 0000000000037040044000288003700000022025 PETER & MAY GMBH GIMME YOUR MONEY AGDEFAULT VERWENDUNGSZWECK 1 00 "+
103
+ "0128E 0000006000000000000000000000016726662000000002222402640000000132150 "
104
+ str.should == out
105
+ end
106
+ end
@@ -0,0 +1,21 @@
1
+ require "#{File.dirname(__FILE__)}/spec_helper"
2
+
3
+ describe KingDta::Helper do
4
+ include KingDta::Helper
5
+
6
+ it "should convert to upper case" do
7
+ convert_text('2&2 GmbH & Co. KG').should == '2&2 GMBH & CO. KG'
8
+ end
9
+
10
+ it "should remove invalid chars" do
11
+ convert_text('@()"=<>!§').should == ''
12
+ end
13
+
14
+ it "should leave valid chars" do
15
+ convert_text('abc-ABC-0123- .,&/+*$%').should == 'ABC-ABC-0123- .,&/+*$%'
16
+ end
17
+
18
+ it "should convert umlaute" do
19
+ convert_text('üöäÜÖÄß').should == 'UEOEAEUEOEAESS'
20
+ end
21
+ end
@@ -0,0 +1,43 @@
1
+ require 'rubygems'
2
+ require 'spec'
3
+ require 'ostruct'
4
+ require 'date'
5
+ require "#{File.dirname(__FILE__)}/../lib/king_dtaus"
6
+
7
+ #Filename der eigenen Kontodaten
8
+ # Beispiel:
9
+ # typ:LK
10
+ # blz:99988811
11
+ # konto:123456
12
+ # bank:Nord-Ostschwaebische Sandbank
13
+ #
14
+ # name:Jodelverein Holladrioe 1863 e.V.
15
+ # zweck:Mitgliedsbeitrag 2003
16
+ # Der Typ ist LK oder GK. Siehe Option -t
17
+ # zweck ist ein optionaler Default-Text, der verwendet wird,
18
+ # falls eine Buchung keinen Text hat.
19
+ # Die Adressdaten der Bank sind optional und werdezum erzeugen
20
+ # des Begleitblatts verwendet
21
+ # bankstrasse:Kieselweg 3
22
+ # bankplz:0815
23
+ # bankort:Felsblock
24
+ def test_kto1
25
+ opts = { :nr => '2880037', :blz => '37040044', :name =>'Gimme your Money AG',
26
+ :bank => 'Commerzbank Köln', :zweck => 'Monatsbeitrag' }
27
+ TestKonto.new(opts)
28
+ end
29
+
30
+ def test_kto2
31
+ opts = { :nr => '2787777', :blz => '37040044', :name =>'Peter & May GmbH',
32
+ :bank => 'Commerzbank Köln', :zweck => 'Monatsbeitrag' }
33
+ TestKonto.new(opts)
34
+ end
35
+
36
+ def test_kto3
37
+ opts = { :nr => '2787777', :blz => '37040044', :name =>'Andrew Müller',
38
+ :bank => 'Commerzbank Köln', :zweck => 'Monatsbeitrag' }
39
+ TestKonto.new(opts)
40
+ end
41
+
42
+ # the test account responds to everything
43
+ class TestKonto < OpenStruct; end
metadata ADDED
@@ -0,0 +1,85 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: king_dtaus
3
+ version: !ruby/object:Gem::Version
4
+ hash: 23
5
+ prerelease: false
6
+ segments:
7
+ - 1
8
+ - 0
9
+ - 0
10
+ version: 1.0.0
11
+ platform: ruby
12
+ authors:
13
+ - Georg Leciejewski
14
+ - Georg Ledermann
15
+ autorequire:
16
+ bindir: bin
17
+ cert_chain: []
18
+
19
+ date: 2010-09-14 00:00:00 +02:00
20
+ default_executable:
21
+ dependencies: []
22
+
23
+ description: DTAUS is a text-based format, to create bank transfers for german banks. This gem helps with the creation of those transfer files.
24
+ email: gl@salesking.eu
25
+ executables: []
26
+
27
+ extensions: []
28
+
29
+ extra_rdoc_files:
30
+ - README.rdoc
31
+ files:
32
+ - .gitignore
33
+ - MIT-LICENSE
34
+ - README.rdoc
35
+ - Rakefile
36
+ - VERSION
37
+ - init.rb
38
+ - lib/king_dta/account.rb
39
+ - lib/king_dta/booking.rb
40
+ - lib/king_dta/dtaus.rb
41
+ - lib/king_dta/helper.rb
42
+ - lib/king_dtaus.rb
43
+ - spec/booking_spec.rb
44
+ - spec/dtaus_spec.rb
45
+ - spec/helper_spec.rb
46
+ - spec/spec_helper.rb
47
+ has_rdoc: true
48
+ homepage: http://github.com/salesking/king_dtaus
49
+ licenses: []
50
+
51
+ post_install_message:
52
+ rdoc_options:
53
+ - --charset=UTF-8
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
+ hash: 3
62
+ segments:
63
+ - 0
64
+ version: "0"
65
+ required_rubygems_version: !ruby/object:Gem::Requirement
66
+ none: false
67
+ requirements:
68
+ - - ">="
69
+ - !ruby/object:Gem::Version
70
+ hash: 3
71
+ segments:
72
+ - 0
73
+ version: "0"
74
+ requirements: []
75
+
76
+ rubyforge_project:
77
+ rubygems_version: 1.3.7
78
+ signing_key:
79
+ specification_version: 3
80
+ summary: Generate DTAUS strings and files
81
+ test_files:
82
+ - spec/spec_helper.rb
83
+ - spec/booking_spec.rb
84
+ - spec/helper_spec.rb
85
+ - spec/dtaus_spec.rb