konto_check_ruby 1.0.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.
- checksums.yaml +7 -0
- data/CHANGELOG.md +26 -0
- data/COPYRIGHT +22 -0
- data/LICENSE +504 -0
- data/README.md +295 -0
- data/bin/konto_check_ruby +202 -0
- data/data/README.md +17 -0
- data/data/blz.lut2f +0 -0
- data/data/iban_regeln.txt +1260 -0
- data/lib/konto_check_ruby/bank_data.rb +421 -0
- data/lib/konto_check_ruby/blz_file.rb +705 -0
- data/lib/konto_check_ruby/check_methods/part1.rb +1634 -0
- data/lib/konto_check_ruby/check_methods/part2.rb +1604 -0
- data/lib/konto_check_ruby/check_methods/part3.rb +1905 -0
- data/lib/konto_check_ruby/check_methods/part4.rb +1738 -0
- data/lib/konto_check_ruby/check_methods/part5.rb +1407 -0
- data/lib/konto_check_ruby/check_methods.rb +147 -0
- data/lib/konto_check_ruby/collation.rb +52 -0
- data/lib/konto_check_ruby/engine.rb +1006 -0
- data/lib/konto_check_ruby/iban_rules.rb +1060 -0
- data/lib/konto_check_ruby/konto_check.rb +1578 -0
- data/lib/konto_check_ruby/lut_file.rb +457 -0
- data/lib/konto_check_ruby/raw.rb +614 -0
- data/lib/konto_check_ruby/retvals.rb +826 -0
- data/lib/konto_check_ruby/search.rb +440 -0
- data/lib/konto_check_ruby/update.rb +176 -0
- data/lib/konto_check_ruby/version.rb +18 -0
- data/lib/konto_check_ruby.rb +42 -0
- metadata +112 -0
data/README.md
ADDED
|
@@ -0,0 +1,295 @@
|
|
|
1
|
+
# konto_check_ruby
|
|
2
|
+
|
|
3
|
+
Copyright (C) 2026 tickettoaster GmbH. LGPL 2.1 or later.
|
|
4
|
+
Source: <https://github.com/provideal/konto_check_ruby>
|
|
5
|
+
|
|
6
|
+
A pure Ruby port of [konto_check](https://sourceforge.net/projects/kontocheck/),
|
|
7
|
+
Michael Plugge's C library for validating German bank accounts.
|
|
8
|
+
No C extension, no native dependencies.
|
|
9
|
+
|
|
10
|
+
* all check digit methods of the Deutsche Bundesbank (00 to E4, including
|
|
11
|
+
all sub-methods) for German account numbers,
|
|
12
|
+
* IBAN generation and validation for German accounts including the
|
|
13
|
+
Bundesbank IBAN rules (rules 0000 to 0057 as of konto_check 6.15),
|
|
14
|
+
IBAN checksum validation for all countries,
|
|
15
|
+
* BIC, creditor identifier (Gläubiger-ID) and structured remittance (IPI)
|
|
16
|
+
checks,
|
|
17
|
+
* bank directory lookups (name, BIC, place, postal code, successor BLZ, ...)
|
|
18
|
+
and searches (by name, place, BIC, BLZ/PLZ ranges, full text),
|
|
19
|
+
* reads the **LUT files** of the original library (`blz.lut2f`, LUT format 2.x)
|
|
20
|
+
and writes them (including the second data set and the index blocks),
|
|
21
|
+
* reads the **bank code files of the Deutsche Bundesbank** directly, in all
|
|
22
|
+
three published formats (fixed width TXT, CSV, XML),
|
|
23
|
+
* drop-in compatible `KontoCheck` and `KontoCheckRaw` modules for users of
|
|
24
|
+
the original [konto_check gem](https://rubygems.org/gems/konto_check).
|
|
25
|
+
|
|
26
|
+
The port is verified bit for bit against the C library: differential tests
|
|
27
|
+
compare millions of randomly generated account numbers for every check
|
|
28
|
+
method and sub-method, all IBAN rules and all bank lookups with the results
|
|
29
|
+
of the original code (see `tools/`).
|
|
30
|
+
|
|
31
|
+
## Installation
|
|
32
|
+
|
|
33
|
+
```ruby
|
|
34
|
+
gem "konto_check_ruby"
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
Requires Ruby >= 3.0, no other dependencies.
|
|
38
|
+
|
|
39
|
+
The version of the ported C library is available as
|
|
40
|
+
`KontoCheckRuby::C_LIBRARY_VERSION` (currently 6.15.0).
|
|
41
|
+
|
|
42
|
+
## Bank data
|
|
43
|
+
|
|
44
|
+
The library needs the bank directory of the Deutsche Bundesbank. Two sources
|
|
45
|
+
are supported:
|
|
46
|
+
|
|
47
|
+
1. **Bundesbank bank code files** ("Bankleitzahlendatei"), downloadable from
|
|
48
|
+
[bundesbank.de](https://www.bundesbank.de/de/aufgaben/unbarer-zahlungsverkehr/serviceangebot/bankleitzahlen/download-bankleitzahlen-602592)
|
|
49
|
+
as TXT (fixed width), CSV or XML. They are published quarterly and can be
|
|
50
|
+
loaded directly:
|
|
51
|
+
|
|
52
|
+
```ruby
|
|
53
|
+
engine = KontoCheckRuby::Engine.new
|
|
54
|
+
engine.load_blz_file("blz-aktuell-txt-data.txt") # or .csv / .xml
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
Note: the current Bundesbank files no longer contain the IBAN rule
|
|
58
|
+
column. konto_check_ruby therefore applies a built-in table of IBAN rules
|
|
59
|
+
per BLZ (`data/iban_regeln.txt`, extracted from the LUT file of
|
|
60
|
+
konto_check 6.15 with bank data of December 2025) to such files. Pass `iban_rules: false` to disable that
|
|
61
|
+
or `iban_rules: "my_rules.txt"` / a Hash `{blz => rule * 100 + version}`
|
|
62
|
+
to supply your own table.
|
|
63
|
+
|
|
64
|
+
2. **LUT files** of the original library (`blz.lut2f`). A LUT file is a
|
|
65
|
+
compressed block format; it may contain two data sets with different
|
|
66
|
+
validity periods, and the currently valid one is chosen automatically.
|
|
67
|
+
The gem ships a LUT file generated from the current Bundesbank data
|
|
68
|
+
(`data/blz.lut2f`, valid from 2026-09-07 to 2026-12-06, IBAN rules from
|
|
69
|
+
the built-in table, see `data/README.md`). **It is the default:** `init`
|
|
70
|
+
without a file name (or `KontoCheck.init` without arguments) loads it.
|
|
71
|
+
You can also use the files distributed with konto_check or generate them
|
|
72
|
+
yourself from a Bundesbank file:
|
|
73
|
+
|
|
74
|
+
```ruby
|
|
75
|
+
KontoCheckRuby::BlzFile.generate_lut("blz-aktuell-txt-data.txt", "blz.lut2f",
|
|
76
|
+
gueltigkeit: "20260907-20261206")
|
|
77
|
+
engine.init("blz.lut2f") # level 5 by default, 0..9 = amount of data loaded
|
|
78
|
+
engine.init # the bundled data/blz.lut2f
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
Files written by konto_check_ruby are readable by the C library and vice
|
|
82
|
+
versa. XML files carry their validity period, for TXT/CSV files pass it
|
|
83
|
+
with `gueltigkeit:` (format `JJJJMMTT-JJJJMMTT`).
|
|
84
|
+
|
|
85
|
+
Data older than its validity period still works; `lut_valid` (or
|
|
86
|
+
`KontoCheck.lut_info`) tells whether the loaded data set is current. The
|
|
87
|
+
test fixtures contain a LUT file from 2023 and a Bundesbank TXT file.
|
|
88
|
+
|
|
89
|
+
### Keeping the data current (self update)
|
|
90
|
+
|
|
91
|
+
The Bundesbank publishes a new bank code file every quarter (validity starts
|
|
92
|
+
in March, June, September and December). `KontoCheckRuby::Update` fetches the
|
|
93
|
+
current file from the
|
|
94
|
+
[download page](https://www.bundesbank.de/de/aufgaben/unbarer-zahlungsverkehr/serviceangebot/bankleitzahlen/download-bankleitzahlen-602592)
|
|
95
|
+
into a local cache directory (`$KONTO_CHECK_RUBY_CACHE`, else
|
|
96
|
+
`~/.cache/konto_check_ruby`) and the engine loads it directly:
|
|
97
|
+
|
|
98
|
+
```ruby
|
|
99
|
+
engine = KontoCheckRuby::Engine.new
|
|
100
|
+
engine.load_current # cached file valid today, downloaded if there is none
|
|
101
|
+
engine.lut_valid # => 4 (LUT2_VALID)
|
|
102
|
+
|
|
103
|
+
result = KontoCheckRuby::Update.update # download only if the file changed
|
|
104
|
+
result.status # => :downloaded or :current
|
|
105
|
+
result.path # => ".../blz-20260907-20261206.xml"
|
|
106
|
+
KontoCheckRuby::Update.update(lut: "blz.lut2f") # additionally write a LUT file
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
`load_current(refresh: :auto)` (default) contacts the server only when no
|
|
110
|
+
cached file is valid for today; `refresh: :always` checks the download page
|
|
111
|
+
on every call, `refresh: :never` works offline. If a download fails, the
|
|
112
|
+
newest cached file is used, and without any cached file the bundled LUT
|
|
113
|
+
file; `engine.last_update_error` holds the reason. Network access uses only
|
|
114
|
+
the standard library (`net/http`); the download is about 5 MB for the XML
|
|
115
|
+
file (`format: :txt` or `:csv` are smaller but need the validity from the
|
|
116
|
+
download page).
|
|
117
|
+
|
|
118
|
+
On the command line: `konto_check_ruby update [LUTFILE]` downloads the
|
|
119
|
+
current file (and optionally writes a LUT file), `konto_check_ruby -d current
|
|
120
|
+
...` uses the cached current file for any command.
|
|
121
|
+
|
|
122
|
+
**LUT file or Bundesbank file?** For a pure Ruby application the LUT format
|
|
123
|
+
brings no advantage any more: loading the Bundesbank XML directly takes about
|
|
124
|
+
as long as loading a level 9 LUT file (70 ms), and all functions work the
|
|
125
|
+
same. The LUT format is still useful to exchange data with the C library or
|
|
126
|
+
its other ports, to bundle the data compactly (1 MB instead of 5 MB) and to
|
|
127
|
+
keep two data sets with different validity periods in one file, which is why
|
|
128
|
+
reading and writing it remains supported. The only thing the Bundesbank files
|
|
129
|
+
lack is the IBAN rule column, which the built-in rule table compensates.
|
|
130
|
+
|
|
131
|
+
## Usage
|
|
132
|
+
|
|
133
|
+
### Ruby API (`KontoCheckRuby::Engine`)
|
|
134
|
+
|
|
135
|
+
```ruby
|
|
136
|
+
require "konto_check_ruby"
|
|
137
|
+
|
|
138
|
+
engine = KontoCheckRuby::Engine.new
|
|
139
|
+
engine.init # bundled data; or init("blz.lut2f", 9), load_blz_file("blz.txt")
|
|
140
|
+
|
|
141
|
+
engine.kto_check_blz("37040044", "532013000") # => 1 (OK)
|
|
142
|
+
engine.kto_check_pz("13", "532013000") # check with an explicit method
|
|
143
|
+
engine.kto_check_regel("10050000", "1111") # with IBAN rules => 18 (OK_KTO_REPLACED)
|
|
144
|
+
|
|
145
|
+
engine.iban_check("DE89 3704 0044 0532 0130 00") # => [1, 1] (IBAN status, account status)
|
|
146
|
+
engine.iban_gen("37040044", "532013000") # => ["DE89370400440532013000", 1]
|
|
147
|
+
engine.iban_bic_gen("37040044", "532013000") # => [1, "DE89 3704 0044 0532 0130 00", "COBADEFFXXX", "37040044", "0532013000"]
|
|
148
|
+
engine.iban2bic("DE89370400440532013000") # => ["COBADEFFXXX", 1, "37040044", "0532013000"]
|
|
149
|
+
engine.bic_check("COBADEFFXXX") # => [1, count]
|
|
150
|
+
engine.ci_check("DE98ZZZ09999999999") # creditor identifier => 1
|
|
151
|
+
|
|
152
|
+
engine.lut_name("37040044") # => ["Commerzbank", 1]
|
|
153
|
+
engine.lut_ort("37040044", 2) # branch 2 => ["Dormagen", 1]
|
|
154
|
+
engine.lut_bic("37040044") # => ["COBADEFFXXX", 1]
|
|
155
|
+
engine.lut_multiple("37040044") # Hash with all fields of all branches
|
|
156
|
+
engine.lut_suche_namen("Sparkasse") # => [1, [flat indexes...]]
|
|
157
|
+
engine.lut_suche_multiple("Sparkasse Köln", true) # => [1, [[37050198, 0]]]
|
|
158
|
+
|
|
159
|
+
engine.retval2txt(-4) # => "die Bankleitzahl ist ungültig"
|
|
160
|
+
engine.retval2txt_short(-4) # => "INVALID_BLZ"
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
All return codes are integer constants in `KontoCheckRuby` (`OK = 1`,
|
|
164
|
+
`FALSE = 0`, `OK_NO_CHK = 2`, `INVALID_BLZ = -4`, ...), identical to the C
|
|
165
|
+
library. Values greater than 0 mean "ok" (possibly with a remark), 0 means
|
|
166
|
+
"wrong", negative values are errors. Functions that return a value and a
|
|
167
|
+
status return `[value, status]`.
|
|
168
|
+
|
|
169
|
+
Several engines with different data sets can be used side by side.
|
|
170
|
+
|
|
171
|
+
### Compatible API (`KontoCheck` / `KontoCheckRaw`)
|
|
172
|
+
|
|
173
|
+
The modules `KontoCheck` (Ruby-like, mostly plain values) and
|
|
174
|
+
`KontoCheckRaw` (arrays of `[value, status]`, like the C extension) have the
|
|
175
|
+
same functions, parameters and return values as the original gem, so
|
|
176
|
+
existing code keeps working:
|
|
177
|
+
|
|
178
|
+
```ruby
|
|
179
|
+
require "konto_check_ruby"
|
|
180
|
+
|
|
181
|
+
KontoCheck.init # bundled data, or KontoCheck.init("blz.lut2f", 9)
|
|
182
|
+
KontoCheck.konto_check?("37040044", "532013000") # => true
|
|
183
|
+
KontoCheck.konto_check("37040044", 532013000) # => 1
|
|
184
|
+
KontoCheck.bank_name("37040044") # => "Commerzbank"
|
|
185
|
+
KontoCheck.bank_alles("37040044") # => [1, 17, "Commerzbank", "Commerzbank Köln", 50447, "Köln", ...]
|
|
186
|
+
KontoCheck.iban_gen(37040044, 532013000) # => "DE89370400440532013000"
|
|
187
|
+
KontoCheck.iban_check("DE89370400440532013000") # => 1
|
|
188
|
+
KontoCheck.suche(ort: "Köln", uniq: 1) # => [37040044, ...]
|
|
189
|
+
KontoCheckRaw.bank_suche_namen("Postbank") # => [names, blzs, branches, status, count]
|
|
190
|
+
KontoCheckRaw.iban_gen("37040044", "532013000") # => [iban, iban_papier, status, bic, blz2, kto2, regel]
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
Both modules use a shared default engine (`KontoCheckRuby.engine`).
|
|
194
|
+
|
|
195
|
+
### Command line
|
|
196
|
+
|
|
197
|
+
```
|
|
198
|
+
konto_check_ruby check 37040044 532013000 # uses the bundled data, -d FILE for another
|
|
199
|
+
konto_check_ruby -d blz-aktuell-txt-data.txt iban DE89370400440532013000
|
|
200
|
+
konto_check_ruby iban-gen 10050000 1111
|
|
201
|
+
konto_check_ruby bank 37040044
|
|
202
|
+
konto_check_ruby search "Sparkasse Köln"
|
|
203
|
+
konto_check_ruby -g 20260907-20261206 generate-lut blz-aktuell-txt-data.txt blz.lut2f
|
|
204
|
+
konto_check_ruby dump blz.lut2f
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
## Performance
|
|
208
|
+
|
|
209
|
+
Measured in-process on the same 2023 LUT file (level 9), C library compiled
|
|
210
|
+
with `-O2`, Ruby 3.3 with and without YJIT, Apple Silicon.
|
|
211
|
+
|
|
212
|
+
One-time costs:
|
|
213
|
+
|
|
214
|
+
| | C library | Ruby port |
|
|
215
|
+
|---|---|---|
|
|
216
|
+
| `require "konto_check_ruby"` | – | 24 ms |
|
|
217
|
+
| init level 9 (all blocks) | 6 ms | 67 ms |
|
|
218
|
+
| init level 0 (BLZ and check methods only) | 0.5 ms | 5 ms |
|
|
219
|
+
| load a Bundesbank TXT file directly | – | 72 ms |
|
|
220
|
+
| first name search (builds the sort index once) | – | 35 ms |
|
|
221
|
+
|
|
222
|
+
Per call, microseconds (200,000 calls each):
|
|
223
|
+
|
|
224
|
+
| Function | C | Ruby | Ruby + YJIT |
|
|
225
|
+
|---|---|---|---|
|
|
226
|
+
| `kto_check_blz` (account check) | 0.03 | 2.8 | 1.5 |
|
|
227
|
+
| `kto_check_pz` | 0.02 | 2.8 | 1.5 |
|
|
228
|
+
| `iban_check` (German IBAN incl. rules) | 0.33 | 22 | 18 |
|
|
229
|
+
| `iban_bic_gen` | 0.14 | 12 | 8 |
|
|
230
|
+
| `lut_name` | 0.004 | 0.6 | 0.4 |
|
|
231
|
+
| `lut_bic` (with rule check) | 0.04 | 3.2 | 2.1 |
|
|
232
|
+
| `lut_suche_namen("Sparkasse")` | 55 | 126 | 48 |
|
|
233
|
+
| `KontoCheck.konto_check?` (compatibility layer) | – | 3.2 | 1.7 |
|
|
234
|
+
|
|
235
|
+
In relative terms the Ruby port is 50 to 100 times slower per call, in
|
|
236
|
+
absolute terms a single operation costs a few microseconds: an account
|
|
237
|
+
check takes about 3 µs, a complete IBAN check about 20 µs, which is not
|
|
238
|
+
noticeable next to a request or a database query. 1,000 account checks take
|
|
239
|
+
about 3 ms (C: 0.03 ms), 1,000 IBAN checks about 22 ms (C: 0.3 ms). The only
|
|
240
|
+
cost you can feel is initialisation (67 ms versus 6 ms), so load the data
|
|
241
|
+
once per process, as the default engine does, not per request. The C
|
|
242
|
+
figures are pure library calls; the C extension of the original gem adds
|
|
243
|
+
Ruby-to-C argument conversion on top, so the gap inside a Ruby application
|
|
244
|
+
is somewhat smaller.
|
|
245
|
+
|
|
246
|
+
## Differences to the C library / original gem
|
|
247
|
+
|
|
248
|
+
* Default output encoding is UTF-8 (the C library defaults to ISO-8859-1).
|
|
249
|
+
`encoding("i")` etc. still switches the encoding of texts and names.
|
|
250
|
+
* Bank names, places etc. are returned as proper UTF-8 Ruby strings.
|
|
251
|
+
* The SCL directory functions (`scl_*`) are not implemented; they return
|
|
252
|
+
`NO_SCL_BLOCKS_LOADED`.
|
|
253
|
+
* A missing IBAN rule block in a LUT file does not disable the IBAN functions
|
|
254
|
+
(the C library refuses them); the standard rule is used instead.
|
|
255
|
+
* LUT files of the old format 1.x are not supported (`LUT1_FILE_USED`).
|
|
256
|
+
* Only zlib compressed (and uncompressed) LUT files are supported; bzip2,
|
|
257
|
+
lzo and lzma compressed files return `KTO_CHECK_UNSUPPORTED_COMPRESSION`.
|
|
258
|
+
* Account numbers containing non-digit characters return `INVALID_KTO`
|
|
259
|
+
(the C library computes with undefined values there).
|
|
260
|
+
* `lut_bic` with a branch index beyond the number of branches always returns
|
|
261
|
+
`LUT2_INDEX_OUT_OF_RANGE` (the C library may return `OK_INVALID_FOR_IBAN`
|
|
262
|
+
for banks with IBAN rules 31..35 due to an unterminated buffer).
|
|
263
|
+
* A failed `init` keeps the previously loaded data (the C library drops it).
|
|
264
|
+
* `init` without a file name loads the bundled LUT file (the C library
|
|
265
|
+
searches `./blz.lut2f`, `/etc/blz.lut2f`, ... instead).
|
|
266
|
+
* If neither data set of a LUT file is currently valid, the younger one is
|
|
267
|
+
loaded (the C library always falls back to the first set).
|
|
268
|
+
|
|
269
|
+
## Development
|
|
270
|
+
|
|
271
|
+
```
|
|
272
|
+
bundle install
|
|
273
|
+
rake test
|
|
274
|
+
```
|
|
275
|
+
|
|
276
|
+
The differential tests in `tools/` need the C library compiled as a small
|
|
277
|
+
test driver; see `tools/README.md`. `tools/PORTING_SPEC.md` and
|
|
278
|
+
`tools/IBAN_PORTING_SPEC.md` describe the porting rules that were followed.
|
|
279
|
+
|
|
280
|
+
## Copyright and license
|
|
281
|
+
|
|
282
|
+
Copyright (C) 2026 tickettoaster GmbH, <https://tickettoaster.de>.
|
|
283
|
+
|
|
284
|
+
konto_check_ruby is a derivative work of konto_check, Copyright (C)
|
|
285
|
+
2002-2023 Michael Plugge, and is licensed like the original under the GNU
|
|
286
|
+
Lesser General Public License, version 2.1 or (at your option) any later
|
|
287
|
+
version (see LICENSE and COPYRIGHT). The `KontoCheck` module is taken from the original
|
|
288
|
+
konto_check gem. The bank data in `data/` comes from the Deutsche Bundesbank
|
|
289
|
+
(see `data/README.md`).
|
|
290
|
+
|
|
291
|
+
Using the gem in your own application, also a closed source one, is
|
|
292
|
+
permitted by the LGPL as long as konto_check_ruby stays a separate library
|
|
293
|
+
(a gem dependency) whose source and license are available to the recipients
|
|
294
|
+
of your application; changes to konto_check_ruby itself must be published
|
|
295
|
+
under the LGPL. This is not legal advice.
|
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
# Copyright (C) 2026 tickettoaster GmbH <https://tickettoaster.de>.
|
|
5
|
+
# Part of konto_check_ruby, a Ruby port of konto_check (Copyright (C)
|
|
6
|
+
# 2002-2023 Michael Plugge); licensed under the GNU Lesser General Public
|
|
7
|
+
# License, version 2.1 or later, see the file LICENSE.
|
|
8
|
+
|
|
9
|
+
# Command line interface of konto_check_ruby.
|
|
10
|
+
#
|
|
11
|
+
# konto_check_ruby [-d DATAFILE] COMMAND ARGS...
|
|
12
|
+
#
|
|
13
|
+
# DATAFILE is a LUT file (blz.lut2f) or a Bundesbank bank code file (TXT,
|
|
14
|
+
# CSV or XML); "current" uses the current Bundesbank file from the local
|
|
15
|
+
# cache (downloaded on demand, see the update command). Without -d the LUT
|
|
16
|
+
# file bundled with the gem is used.
|
|
17
|
+
|
|
18
|
+
require "optparse"
|
|
19
|
+
require_relative "../lib/konto_check_ruby"
|
|
20
|
+
|
|
21
|
+
options = { data: nil, level: 9 }
|
|
22
|
+
parser = OptionParser.new do |o|
|
|
23
|
+
o.banner = <<~BANNER
|
|
24
|
+
Usage: konto_check_ruby [options] COMMAND [ARGS]
|
|
25
|
+
|
|
26
|
+
Commands:
|
|
27
|
+
check BLZ KTO check an account number (with IBAN rules: check-regel)
|
|
28
|
+
check-pz METHODE KTO check an account number with a given check method (e.g. 00, 13a)
|
|
29
|
+
iban IBAN validate an IBAN
|
|
30
|
+
iban-gen BLZ KTO generate the IBAN and BIC for an account
|
|
31
|
+
bank BLZ [FILIALE] show the bank data of a BLZ
|
|
32
|
+
search TEXT search banks (e.g. "Sparkasse Köln", "50667@plz", "COBADEFF@bic")
|
|
33
|
+
generate-lut IN OUT generate a LUT file from a Bundesbank file
|
|
34
|
+
dump LUT show the directory of a LUT file
|
|
35
|
+
info [LUT] show the info block(s) of a LUT file / the loaded data
|
|
36
|
+
update [LUTFILE] download the current Bundesbank file into the cache
|
|
37
|
+
(and optionally write a LUT file from it)
|
|
38
|
+
version
|
|
39
|
+
|
|
40
|
+
Options:
|
|
41
|
+
BANNER
|
|
42
|
+
o.on("-d", "--data FILE", "LUT file, Bundesbank file (TXT/CSV/XML) or 'current'; default: the bundled blz.lut2f") { |v| options[:data] = v }
|
|
43
|
+
o.on("--cache DIR", "cache directory for 'current'/update (default #{KontoCheckRuby::Update.cache_dir})") { |v| options[:cache] = v }
|
|
44
|
+
o.on("--force", "update: download even if the file is cached") { options[:force] = true }
|
|
45
|
+
o.on("-l", "--level N", Integer, "init level for LUT files (0..9, default 9)") { |v| options[:level] = v }
|
|
46
|
+
o.on("-g", "--gueltigkeit RANGE", "validity JJJJMMTT-JJJJMMTT (generate-lut, Bundesbank files)") { |v| options[:gueltigkeit] = v }
|
|
47
|
+
o.on("-h", "--help") do
|
|
48
|
+
puts o
|
|
49
|
+
exit
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
parser.parse!
|
|
53
|
+
|
|
54
|
+
command = ARGV.shift
|
|
55
|
+
if command.nil?
|
|
56
|
+
puts parser
|
|
57
|
+
exit 1
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
engine = KontoCheckRuby::Engine.new
|
|
61
|
+
|
|
62
|
+
def load_data(engine, options)
|
|
63
|
+
file = options[:data]
|
|
64
|
+
code = if file == "current"
|
|
65
|
+
c = engine.load_current(dir: options[:cache] || KontoCheckRuby::Update.cache_dir)
|
|
66
|
+
warn "download failed (#{engine.last_update_error}), using #{engine.current_lutfile_name[0]}" if engine.last_update_error
|
|
67
|
+
c
|
|
68
|
+
elsif file && file =~ /\.(txt|csv|xml)\z/i
|
|
69
|
+
engine.load_blz_file(file, gueltigkeit: options[:gueltigkeit])
|
|
70
|
+
else
|
|
71
|
+
engine.init(file, options[:level])
|
|
72
|
+
end
|
|
73
|
+
return if code > 0 || code == KontoCheckRuby::LUT2_PARTIAL_OK
|
|
74
|
+
warn "could not load bank data#{file ? " from #{file}" : ''}: #{engine.retval2txt_short(code)} (#{engine.retval2txt(code)})"
|
|
75
|
+
exit 2
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def status(engine, code)
|
|
79
|
+
"#{code} #{engine.retval2txt_short(code)}: #{engine.retval2txt(code)}"
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
case command
|
|
83
|
+
when "check", "check-regel"
|
|
84
|
+
load_data(engine, options)
|
|
85
|
+
blz, kto = ARGV
|
|
86
|
+
abort "usage: check BLZ KTO" unless blz && kto
|
|
87
|
+
code = command == "check" ? engine.kto_check_blz(blz, kto) : engine.kto_check_regel(blz, kto)
|
|
88
|
+
puts status(engine, code)
|
|
89
|
+
exit(code > 0 ? 0 : 1)
|
|
90
|
+
when "check-pz"
|
|
91
|
+
pz, kto, blz = ARGV
|
|
92
|
+
abort "usage: check-pz METHODE KTO [BLZ]" unless pz && kto
|
|
93
|
+
code = engine.kto_check_pz(pz, kto, blz)
|
|
94
|
+
puts status(engine, code)
|
|
95
|
+
exit(code > 0 ? 0 : 1)
|
|
96
|
+
when "iban"
|
|
97
|
+
load_data(engine, options)
|
|
98
|
+
iban = ARGV[0] or abort "usage: iban IBAN"
|
|
99
|
+
code, kc = engine.iban_check(iban)
|
|
100
|
+
puts "IBAN: #{status(engine, code)}"
|
|
101
|
+
puts "Konto: #{status(engine, kc)}"
|
|
102
|
+
if code > 0 && iban.gsub(/\s/, "")[0, 2].casecmp("DE").zero? && engine.initialized?
|
|
103
|
+
bic, ret, blz, kto = engine.iban2bic(iban)
|
|
104
|
+
puts "BLZ #{blz}, Konto #{kto}, BIC #{bic} (#{engine.retval2txt_short(ret)})"
|
|
105
|
+
name, r = engine.lut_name(blz)
|
|
106
|
+
puts "Bank: #{name}, #{engine.lut_ort(blz)[0]}" if r == KontoCheckRuby::OK
|
|
107
|
+
end
|
|
108
|
+
exit(code > 0 ? 0 : 1)
|
|
109
|
+
when "iban-gen"
|
|
110
|
+
load_data(engine, options)
|
|
111
|
+
blz, kto = ARGV
|
|
112
|
+
abort "usage: iban-gen BLZ KTO" unless blz && kto
|
|
113
|
+
ret, iban, bic, blz2, kto2 = engine.iban_bic_gen(blz, kto)
|
|
114
|
+
puts status(engine, ret)
|
|
115
|
+
if iban
|
|
116
|
+
puts "IBAN: #{iban}"
|
|
117
|
+
puts "BIC: #{bic}"
|
|
118
|
+
puts "verwendete BLZ/Konto: #{blz2} / #{kto2}" if blz2 != blz || kto2 != kto.rjust(10, "0")
|
|
119
|
+
end
|
|
120
|
+
exit(ret > 0 ? 0 : 1)
|
|
121
|
+
when "bank"
|
|
122
|
+
load_data(engine, options)
|
|
123
|
+
blz = ARGV[0] or abort "usage: bank BLZ [FILIALE]"
|
|
124
|
+
fil = (ARGV[1] || 0).to_i
|
|
125
|
+
m = engine.lut_multiple(blz)
|
|
126
|
+
if m[:retval] <= 0 && m[:retval] != KontoCheckRuby::LUT2_PARTIAL_OK
|
|
127
|
+
puts status(engine, m[:retval])
|
|
128
|
+
exit 1
|
|
129
|
+
end
|
|
130
|
+
if fil >= m[:cnt]
|
|
131
|
+
puts status(engine, KontoCheckRuby::LUT2_INDEX_OUT_OF_RANGE)
|
|
132
|
+
exit 1
|
|
133
|
+
end
|
|
134
|
+
f = ->(k) { m[k] ? m[k][fil] : "-" }
|
|
135
|
+
bic, bret = engine.lut_bic(blz, fil)
|
|
136
|
+
puts "BLZ: #{m[:blz]} (#{m[:cnt]} Stelle#{m[:cnt] == 1 ? '' : 'n'}, Filiale #{fil})"
|
|
137
|
+
puts "Name: #{f.call(:name)}"
|
|
138
|
+
puts "Kurzname: #{f.call(:name_kurz)}"
|
|
139
|
+
puts "PLZ / Ort: #{f.call(:plz)} #{f.call(:ort)}"
|
|
140
|
+
puts "BIC: #{bic} (#{engine.retval2txt_short(bret)})"
|
|
141
|
+
puts "Prüfziffer: #{m[:pz] ? KontoCheckRuby::BlzFile.pz_to_string(m[:pz]) : '-'}"
|
|
142
|
+
puts "PAN: #{f.call(:pan)}"
|
|
143
|
+
puts "Datensatz-Nr.: #{f.call(:nr)}"
|
|
144
|
+
puts "Änderung: #{f.call(:aenderung)}"
|
|
145
|
+
puts "Löschung: #{f.call(:loeschung)}"
|
|
146
|
+
puts "Nachfolge-BLZ: #{f.call(:nachfolge_blz)}"
|
|
147
|
+
r = f.call(:iban_regel)
|
|
148
|
+
puts "IBAN-Regel: #{r.is_a?(Integer) ? format('%04d.%02d', r / 100, r % 100) : r}"
|
|
149
|
+
when "search"
|
|
150
|
+
load_data(engine, options)
|
|
151
|
+
text = ARGV.join(" ")
|
|
152
|
+
abort "usage: search TEXT" if text.empty?
|
|
153
|
+
code, pairs = engine.lut_suche_multiple(text, true)
|
|
154
|
+
if code < 0 || pairs.empty?
|
|
155
|
+
puts status(engine, code == KontoCheckRuby::OK ? KontoCheckRuby::KEY_NOT_FOUND : code)
|
|
156
|
+
exit 1
|
|
157
|
+
end
|
|
158
|
+
pairs.each do |blz, zw|
|
|
159
|
+
name, = engine.lut_name(blz.to_s, zw)
|
|
160
|
+
ort, = engine.lut_ort(blz.to_s, zw)
|
|
161
|
+
bic, = engine.lut_bic_int(blz.to_s, zw)
|
|
162
|
+
puts format("%08d %-11s %-40s %s", blz, bic.to_s.strip, name.to_s[0, 40], ort)
|
|
163
|
+
end
|
|
164
|
+
puts "#{pairs.size} Treffer#{code == KontoCheckRuby::SOME_KEYS_NOT_FOUND ? ' (nicht alle Suchbegriffe gefunden)' : ''}"
|
|
165
|
+
when "generate-lut"
|
|
166
|
+
input, output = ARGV
|
|
167
|
+
abort "usage: generate-lut INPUT OUTPUT" unless input && output
|
|
168
|
+
code = KontoCheckRuby::BlzFile.generate_lut(input, output, gueltigkeit: options[:gueltigkeit], felder: 9, filialen: true,
|
|
169
|
+
user_info: "generiert von konto_check_ruby #{KontoCheckRuby::VERSION}")
|
|
170
|
+
puts status(engine, code)
|
|
171
|
+
exit(code > 0 ? 0 : 1)
|
|
172
|
+
when "dump"
|
|
173
|
+
lut = ARGV[0] or abort "usage: dump LUT"
|
|
174
|
+
code, dump = KontoCheckRuby::LutFile.dump(lut)
|
|
175
|
+
puts(code == KontoCheckRuby::OK ? dump : status(engine, code))
|
|
176
|
+
when "info"
|
|
177
|
+
if ARGV[0]
|
|
178
|
+
code, i1, i2, v1, v2 = engine.lut_info(ARGV[0])
|
|
179
|
+
puts status(engine, code)
|
|
180
|
+
puts "\n1. Datensatz (#{engine.retval2txt_short(v1)}):\n#{i1}" if i1
|
|
181
|
+
puts "\n2. Datensatz (#{engine.retval2txt_short(v2)}):\n#{i2}" if i2
|
|
182
|
+
else
|
|
183
|
+
load_data(engine, options)
|
|
184
|
+
puts engine.lut_info[1]
|
|
185
|
+
puts "Gültigkeit: #{engine.retval2txt_short(engine.lut_valid)}"
|
|
186
|
+
end
|
|
187
|
+
when "update"
|
|
188
|
+
begin
|
|
189
|
+
r = KontoCheckRuby::Update.update(dir: options[:cache] || KontoCheckRuby::Update.cache_dir, lut: ARGV[0], force: options[:force])
|
|
190
|
+
puts "#{r.status == :downloaded ? 'downloaded' : 'already cached'}: #{r.path} (gültig #{r.valid_from}-#{r.valid_to})"
|
|
191
|
+
puts "LUT file written: #{r.lut}" if r.lut
|
|
192
|
+
rescue KontoCheckRuby::Update::Error => e
|
|
193
|
+
warn e.message
|
|
194
|
+
exit 2
|
|
195
|
+
end
|
|
196
|
+
when "version"
|
|
197
|
+
puts engine.version
|
|
198
|
+
else
|
|
199
|
+
warn "unknown command #{command}"
|
|
200
|
+
puts parser
|
|
201
|
+
exit 1
|
|
202
|
+
end
|
data/data/README.md
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# Bundled bank data
|
|
2
|
+
|
|
3
|
+
Copyright (C) 2026 tickettoaster GmbH (compilation); the bank data itself is
|
|
4
|
+
published by the Deutsche Bundesbank.
|
|
5
|
+
|
|
6
|
+
`blz.lut2f` is a LUT file generated by konto_check_ruby
|
|
7
|
+
(`KontoCheckRuby::Update.update(lut: ...)`) from the current
|
|
8
|
+
"Bankleitzahlendatei" of the Deutsche Bundesbank
|
|
9
|
+
(https://www.bundesbank.de/de/aufgaben/unbarer-zahlungsverkehr/serviceangebot/bankleitzahlen/download-bankleitzahlen-602592,
|
|
10
|
+
XML variant, validity 2026-09-07 to 2026-12-06). The IBAN rules were added
|
|
11
|
+
from `iban_regeln.txt`, since the Bundesbank files no longer contain them.
|
|
12
|
+
|
|
13
|
+
`iban_regeln.txt` maps BLZ to IBAN rule (rule * 100 + version); it was
|
|
14
|
+
extracted from the LUT file `blz.lut2f` of konto_check 6.15 (bank data of
|
|
15
|
+
December 2025, https://sourceforge.net/projects/kontocheck/).
|
|
16
|
+
|
|
17
|
+
To refresh the data yourself: `konto_check_ruby update path/to/blz.lut2f`.
|
data/data/blz.lut2f
ADDED
|
Binary file
|