iban_bic 0.1.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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: c52896535d5704a64d38733ff91cd49356d4acda
4
+ data.tar.gz: 569ccc510d44e3da5522caab6a45f805c34ea93a
5
+ SHA512:
6
+ metadata.gz: c9d1aa2265b7692f04fd562c6d0bc652e7108bf6283b7526259cd1c28b3181c470936d24609b267ab7ceb39240300c137aaa7d56667e75d5c05f473f894b079b
7
+ data.tar.gz: b256ef1d47c347a273a56a0d1ff0e4bc3fead2be3d55131a52b5ae3a9c3c709c2db42740a8ba72fbc281e586a661985a0f9e3ec9617f3038a044aea7476408ed
data/README.md ADDED
@@ -0,0 +1,101 @@
1
+ # IBAN + BIC
2
+ When IBAN validation is not enough.
3
+
4
+ [![Travis](https://img.shields.io/travis/podemos-info/iban_bic/master.svg)](https://travis-ci.org/podemos-info/iban_bic)
5
+ [![Codecov](https://img.shields.io/codecov/c/github/podemos-info/iban_bic.svg)](https://codecov.io/gh/podemos-info/iban_bic)
6
+ [![Scrutinizer](https://img.shields.io/scrutinizer/g/podemos-info/iban_bic.svg)](https://scrutinizer-ci.com/g/podemos-info/iban_bic/)
7
+ [![Dependency Status](https://www.versioneye.com/user/projects/59d393190fb24f0046190d85/badge.svg?style=flat-square)](https://www.versioneye.com/user/projects/59d393190fb24f0046190d85?style=flat)
8
+
9
+ ## Features
10
+ * IBAN validation (`ActiveModel::EachValidator` and control digits calculator function).
11
+ * National account digits control validation (currently only ES included, others countries can be added).
12
+ * Associated tags to countries (currently only SEPA tag is available).
13
+ * BICs mapping from IBAN bank code part: COUNTRY + BANK => BIC code.
14
+ * Currently, static data only includes some ES banks, PRs are welcomed.
15
+ * Optional database model to allow apps to dynamically add new BICs mapping.
16
+
17
+ ## Usage
18
+
19
+ 1. Validator: add IBAN validation to your models.
20
+
21
+ ```ruby
22
+ validates :iban, iban: true
23
+ ```
24
+
25
+ You can also validate that IBAN is from a SEPA country.
26
+
27
+ ```ruby
28
+ validates :iban, iban: { tags: [:sepa] }
29
+ ```
30
+
31
+ 2. IBAN control digits calculation
32
+
33
+ ```ruby
34
+ 2.4.1 :001 > IbanBic.calculate_check("ES0000030000300000000000")
35
+ => 87
36
+ ```
37
+
38
+ 3. IBAN parsing
39
+
40
+ ```ruby
41
+ 2.4.1 :001 > IbanBic.parse("ES8700030000300000000000")
42
+ => {"country"=>"ES", "iban_check"=>"87", "bank"=>"0003", "branch"=>"0000", "check"=>"30", "account"=>"0000000000"}
43
+ ```
44
+
45
+ 4. BIC calculation (bank code must be in the static file or in the database)
46
+
47
+ ```ruby
48
+ 2.4.1 :009 > IbanBic.calculate_bic("ES8700030000300000000000")
49
+ => "BDEPESM1XXX"
50
+ ```
51
+
52
+ ## Installation
53
+
54
+ 1. Add this line to your application's Gemfile
55
+
56
+ ```ruby
57
+ gem "iban_bic"
58
+ ```
59
+
60
+ 2. Update bundle
61
+
62
+ ```bash
63
+ $ bundle
64
+ ```
65
+
66
+ 3. Run installer
67
+
68
+ 3.a. Using BICs dynamic data from database
69
+
70
+ Add a `bics` table to your database and an initializer file for configuration:
71
+
72
+ ```bash
73
+ $ bundle exec rails generate iban_bic:install
74
+ $ bundle exec rake db:migrate
75
+ ```
76
+
77
+ Load static data to the created `bics` table:
78
+
79
+ ```bash
80
+ $ bundle exec rake iban_bic:load_data
81
+ ```
82
+
83
+ 3.b. Using static data from YAML files
84
+
85
+ Create an initializer file for configuration:
86
+
87
+ ```bash
88
+ $ bundle exec rails generate iban_bic:install --with-static-data
89
+ ```
90
+
91
+ 4. Customize initializer if needed, adding validations for new countries, or overriding YAML files.
92
+
93
+ ## TO-DO
94
+
95
+ * Faker data generation
96
+
97
+ ## Contributing
98
+ Contribution directions go here.
99
+
100
+ ## License
101
+ The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
data/Rakefile ADDED
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ begin
4
+ require "bundler/setup"
5
+ rescue LoadError
6
+ puts "You must `gem install bundler` and `bundle install` to run rake tasks"
7
+ end
8
+
9
+ require "rdoc/task"
10
+
11
+ RDoc::Task.new(:rdoc) do |rdoc|
12
+ rdoc.rdoc_dir = "rdoc"
13
+ rdoc.title = "IbanBic"
14
+ rdoc.options << "--line-numbers"
15
+ rdoc.rdoc_files.include("README.md")
16
+ rdoc.rdoc_files.include("lib/**/*.rb")
17
+ end
18
+
19
+ require "bundler/gem_tasks"
20
+ require "rspec/core/rake_task"
21
+
22
+ RSpec::Core::RakeTask.new("spec")
23
+ task default: :spec
data/data/bics/es.yml ADDED
@@ -0,0 +1,293 @@
1
+ "0003": BDEPESM1XXX
2
+ "0004": POPUESMMXXX
3
+ "0011": ALLFESMMXXX
4
+ "0019": DEUTESBBXXX
5
+ "0021": BCNDESM1XXX
6
+ "0030": ESPCESMMXXX
7
+ "0031": CAGLESMMXXX
8
+ "0036": SABNESMMXXX
9
+ "0038": BSSSESM2XXX
10
+ "0042": BSABESBBXXX
11
+ "0046": GALEES2GXXX
12
+ "0049": BSCHESMMXXX
13
+ "0057": BVADESMMXXX
14
+ "0058": BNPAESMMXXX
15
+ "0059": MADRESMMXXX
16
+ "0061": BMARES2MXXX
17
+ "0065": BARCESMMXXX
18
+ "0072": PSTRESMMXXX
19
+ "0073": OPENESMMXXX
20
+ "0075": POPUESMMXXX
21
+ "0078": BAPUES22XXX
22
+ "0081": BSABESBBXXX
23
+ "0082": POPUESMMXXX
24
+ "0083": RENBESMMXXX
25
+ "0086": NORTESMMXXX
26
+ "0093": CAIXESBBXXX
27
+ "0094": BVALESMMXXX
28
+ "0106": LOYDESMMXXX
29
+ "0107": BNLIESM1XXX
30
+ "0108": SOGEESMMXXX
31
+ "0113": INBBESM1XXX
32
+ "0121": OCBAESM1XXX
33
+ "0122": CITIES2XXXX
34
+ "0125": BAOFESM1XXX
35
+ "0128": BKBKESMMXXX
36
+ "0129": INALESM1XXX
37
+ "0130": CGDIESMMXXX
38
+ "0131": BESMESMMXXX
39
+ "0132": PRNEESM1XXX
40
+ "0133": MIKBESB1XXX
41
+ "0136": AREBESMMXXX
42
+ "0138": BKOAES22XXX
43
+ "0144": PARBESMXXXX
44
+ "0145": DEUTESM1XXX
45
+ "0149": BNPAESMSXXX
46
+ "0151": CHASESM3XXX
47
+ "0152": BPLCESMMXXX
48
+ "0154": BSUIESMMXXX
49
+ "0155": BRASESMMXXX
50
+ "0156": ABNAESMMXXX
51
+ "0159": COBAESMXTMA
52
+ "0160": BOTKESMXXXX
53
+ "0161": BKTRESM1XXX
54
+ "0162": MIDLESMXXXX
55
+ "0167": GEBAESMMXXX
56
+ "0168": BBRUESMXXXX
57
+ "0169": NACNESMMXXX
58
+ "0182": BBVAESMMXXX
59
+ "0184": BEDFESM1XXX
60
+ "0186": BFIVESBBXXX
61
+ "0188": ALCLESMMXXX
62
+ "0190": BBPIESMMXXX
63
+ "0196": WELAESMMXXX
64
+ "0198": BCOEESMMXXX
65
+ "0200": PRVBESB1XXX
66
+ "0205": DECRESM1XXX
67
+ "0211": PROAESMMXXX
68
+ "0216": POHIESMMXXX
69
+ "0217": HLFXESMMXXX
70
+ "0218": FCEFESM1XXX
71
+ "0219": BMCEESMMXXX
72
+ "0220": FIOFESM1XXX
73
+ "0223": GEECESB1XXX
74
+ "0224": SCFBESMMXXX
75
+ "0225": FIEIESM1XXX
76
+ "0226": UBSWESMMXXX
77
+ "0227": UNOEESM1XXX
78
+ "0228": IXIUESM1XXX
79
+ "0229": POPLESMMXXX
80
+ "0231": DSBLESMMXXX
81
+ "0232": INVLESMMXXX
82
+ "0233": POPIESMMXXX
83
+ "0234": CCOCESMMXXX
84
+ "0235": PICHESMMXXX
85
+ "0236": LOYIESMMXXX
86
+ "0237": CSURES2CXXX
87
+ "0238": PSTRESMMXXX
88
+ "0239": EVOBESMMXXX
89
+ "0240": BCCAESMMXXX
90
+ "0487": GBMNESMMXXX
91
+ "0488": BFASESMMXXX
92
+ "1000": ICROESMMXXX
93
+ "1113": BSUDESM1XXX
94
+ "1116": SCSIESM1XXX
95
+ "1127": SCBLESM1XXX
96
+ "1156": IRVTESM1XXX
97
+ "1164": ESBFESM1XXX
98
+ "1168": BNACESM1XXX
99
+ "1173": COURESB1XXX
100
+ "1182": HYVEESM1XXX
101
+ "1191": HANDES21XXX
102
+ "1193": PKBSES21XXX
103
+ "1196": AEEVESM1XXX
104
+ "1197": BILLESB1XXX
105
+ "1199": CRGEESM1XXX
106
+ "1209": ABCMESM1XXX
107
+ "1210": REDEESM1XXX
108
+ "1221": PNBMESM1XXX
109
+ "1224": RHRHESM1XXX
110
+ "1227": BSSAESB1XXX
111
+ "1231": BOCAES21XXX
112
+ "1233": BCMAESM1XXX
113
+ "1234": PRBAESM1XXX
114
+ "1236": HELAESM1XXX
115
+ "1238": BIMEESM1XXX
116
+ "1240": LOFPESB1XXX
117
+ "1241": STOLESM1XXX
118
+ "1242": SOLAESB1XXX
119
+ "1245": BEIVESM1XXX
120
+ "1248": WAFAESM1XXX
121
+ "1249": NPBSES21XXX
122
+ "1251": IHZUES21XXX
123
+ "1255": AARBESM1XXX
124
+ "1451": AGRIESB1XXX
125
+ "1454": NEWGESM1XXX
126
+ "1457": LLISESM1XXX
127
+ "1459": PRABESMMXXX
128
+ "1460": CRESESMMXXX
129
+ "1462": ASSCESM1XXX
130
+ "1463": PSABESM1XXX
131
+ "1464": NFFSESM1XXX
132
+ "1465": INGDESMMXXX
133
+ "1466": FRANESM1XXX
134
+ "1467": EHYPESMXXXX
135
+ "1469": SHSAESM1XXX
136
+ "1470": BPIPESM1XXX
137
+ "1472": UCSSESM1XXX
138
+ "1473": PRIBESMXXXX
139
+ "1474": CITIESMXSEC
140
+ "1475": CCSEESM1XXX
141
+ "1478": MLIBESM1XXX
142
+ "1479": NATXESMMXXX
143
+ "1480": VOWAES21XXX
144
+ "1485": BOFAES2XXXX
145
+ "1488": PICTESMMXXX
146
+ "1490": SELFESMMXXX
147
+ "1491": TRIOESMMXXX
148
+ "1494": BCITESMMXXX
149
+ "1497": ESSIESMMXXX
150
+ "1501": DPBBESM1XXX
151
+ "1502": IKBDESM1XXX
152
+ "1505": ARABESMMXXX
153
+ "1506": MLCBESM1XXX
154
+ "1522": EFGBESMMXXX
155
+ "1524": UBIBESMMXXX
156
+ "1525": BCDMESMMXXX
157
+ "1534": KBLXESMMXXX
158
+ "1538": ICBKESMMXXX
159
+ "1544": BACAESMMXXX
160
+ "1545": AGRIESMMXXX
161
+ "1550": ETICES21XXX
162
+ "1716": EXCHESM1XXX
163
+ "2000": CECAESMMXXX
164
+ "2010": CECAESMM010
165
+ "2013": CESCESBBXXX
166
+ "2017": CECAESMM017
167
+ "2018": CAIXESBBXXX
168
+ "2024": CSURES2CXXX
169
+ "2031": CECAESMM031
170
+ "2038": CAHMESMMXXX
171
+ "2043": CECAESMM043
172
+ "2045": CECAESMM045
173
+ "2048": CECAESMM048
174
+ "2051": CECAESMM051
175
+ "2052": CAHMESMMXXX
176
+ "2054": CAIXESBBXXX
177
+ "2056": CECAESMM056
178
+ "2059": BBVAESMMXXX
179
+ "2065": CAIXESBBXXX
180
+ "2066": CECAESMM066
181
+ "2069": CAHMESMMXXX
182
+ "2074": BBVAESMMXXX
183
+ "2077": CAHMESMMXXX
184
+ "2080": CAGLESMMXXX
185
+ "2081": CECAESMM081
186
+ "2085": CAZRES2ZXXX
187
+ "2086": CAZRES2ZXXX
188
+ "2090": BSABESBBXXX
189
+ "2091": CAGLESMMXXX
190
+ "2095": BASKES2BXXX
191
+ "2096": CSPAES2LXXX
192
+ "2097": BASKES2BXXX
193
+ "2099": CECAESMM099
194
+ "2100": CAIXESBBXXX
195
+ "2101": BASKES2BXXX
196
+ "2103": UCJAES2MXXX
197
+ "2104": CSSOES2SXXX
198
+ "2105": CECAESMM105
199
+ "2106": CAIXESBBXXX
200
+ "2107": BBVAESMMXXX
201
+ "2108": CSPAES2L108
202
+ "3001": BCOEESMM001
203
+ "3005": BCOEESMM005
204
+ "3007": BCOEESMM007
205
+ "3008": BCOEESMM008
206
+ "3009": BCOEESMM009
207
+ "3016": BCOEESMM016
208
+ "3017": BCOEESMM017
209
+ "3018": BCOEESMM018
210
+ "3020": BCOEESMM020
211
+ "3023": BCOEESMM023
212
+ "3025": CDENESBBXXX
213
+ "3029": CCRIES2A029
214
+ "3035": CLPEES2MXXX
215
+ "3045": CCRIES2A045
216
+ "3058": CCRIES2AXXX
217
+ "3059": BCOEESMM059
218
+ "3060": BCOEESMM060
219
+ "3063": BCOEESMM063
220
+ "3067": BCOEESMM067
221
+ "3070": BCOEESMM070
222
+ "3076": BCOEESMM076
223
+ "3080": BCOEESMM080
224
+ "3081": BCOEESMM081
225
+ "3082": CCRIES2AXXX
226
+ "3084": CVRVES2BXXX
227
+ "3085": BCOEESMM085
228
+ "3089": BCOEESMM089
229
+ "3095": CCRIES2A095
230
+ "3096": BCOEESMM096
231
+ "3098": BCOEESMM098
232
+ "3102": CCRIES2A102
233
+ "3104": BCOEESMM104
234
+ "3105": CCRIES2A105
235
+ "3110": BCOEESMM110
236
+ "3111": BCOEESMM111
237
+ "3112": CCRIES2A112
238
+ "3113": BCOEESMM113
239
+ "3115": BCOEESMM115
240
+ "3116": BCOEESMM116
241
+ "3117": BCOEESMM117
242
+ "3118": CCRIES2A118
243
+ "3119": CCRIES2A119
244
+ "3121": CCRIES2A121
245
+ "3123": CCRIES2A123
246
+ "3127": BCOEESMM127
247
+ "3130": BCOEESMM130
248
+ "3134": BCOEESMM134
249
+ "3135": CCRIES2A135
250
+ "3138": BCOEESMM138
251
+ "3140": BCOEESMM140
252
+ "3144": BCOEESMM144
253
+ "3146": CCCVESM1XXX
254
+ "3150": BCOEESMM150
255
+ "3152": CCRIES2A152
256
+ "3157": CCRIES2A157
257
+ "3159": BCOEESMM159
258
+ "3160": CCRIES2A160
259
+ "3162": BCOEESMM162
260
+ "3165": CCRIES2A165
261
+ "3166": BCOEESMM166
262
+ "3172": CCOCESMMXXX
263
+ "3174": BCOEESMM174
264
+ "3177": CCRIES2AXXX
265
+ "3179": CCRIES2A179
266
+ "3183": CASDESBBXXX
267
+ "3186": CCRIES2A186
268
+ "3187": BCOEESMM187
269
+ "3190": BCOEESMM190
270
+ "3191": BCOEESMM191
271
+ "3501": RENTESMMXXX
272
+ "3524": AHCFESMMXXX
273
+ "3563": MISVESMMXXX
274
+ "3575": INSGESMMXXX
275
+ "3604": CAPIESMMXXX
276
+ "3641": LISEESMMXXX
277
+ "3656": CSSOES2SFIN
278
+ "3661": MLCEESMMXXX
279
+ "3669": IVALESMMXXX
280
+ "3682": GVCBESBBETB
281
+ "6706": ORUNESM1XXX
282
+ "6814": MNTYESMMXXX
283
+ "6852": BMEUESM1XXX
284
+ "8233": CSFAESM1XXX
285
+ "8512": UCINESMMXXX
286
+ "8835": SBFCESMMXXX
287
+ "9000": ESPBESMMXXX
288
+ "9020": IPAYESMMXXX
289
+ "9091": XBCNESBBXXX
290
+ "9092": XRBVES2BXXX
291
+ "9093": XRVVESVVXXX
292
+ "9094": MEFFESBBXXX
293
+ "9096": IBRCESMMXXX
@@ -0,0 +1,186 @@
1
+ AD:
2
+ parts: (?<iban_check>\d{2}) (?<bank>\d{4}) (?<branch>\d{4}) (?<account>[A-Z0-9]{12})
3
+ tags:
4
+ AL:
5
+ parts: (?<iban_check>\d{2}) (?<bank>\d{3}) (?<branch>\d{4}) (?<check>\d) (?<account>[A-Z0-9]{16})
6
+ tags:
7
+ AT:
8
+ parts: (?<iban_check>\d{2}) (?<bank>\d{5}) (?<account>\d{11})
9
+ tags: sepa
10
+ AZ:
11
+ parts: (?<iban_check>\d{2}) (?<bank>\d{4}) (?<account>[A-Z0-9]{20})
12
+ tags:
13
+ BA:
14
+ parts: (?<iban_check>39) (?<bank>\d{3}) (?<branch>\d{3}) (?<account>\d{8}) (?<check>\d{2})
15
+ tags:
16
+ BE:
17
+ parts: (?<iban_check>\d{2}) (?<bank>\d{3}) (?<account>\d{7}) (?<check>\d{2})
18
+ tags: sepa
19
+ BG:
20
+ parts: (?<iban_check>\d{2}) (?<bank>[A-Z]{4}) (?<branch>\d{4}) \d{2} (?<account>[A-Z0-9]{8})
21
+ tags: sepa
22
+ BH:
23
+ parts: (?<iban_check>\d{2}) (?<bank>[A-Z]{4}) (?<account>[A-Z0-9]{14})
24
+ tags:
25
+ BR:
26
+ parts: (?<iban_check>\d{2}) (?<bank>\d{8}) (?<branch>\d{5}) (?<account>\d{10}) [A-Z][A-Z0-9]
27
+ tags:
28
+ CH:
29
+ parts: (?<iban_check>\d{2}) (?<bank>\d{5}) (?<account>[A-Z0-9]{12})
30
+ tags: sepa
31
+ CR:
32
+ parts: (?<iban_check>\d{2}) (?<bank>0\d{3}) (?<account>\d{14})
33
+ tags:
34
+ CY:
35
+ parts: (?<iban_check>\d{2}) (?<bank>\d{3}) (?<branch>\d{5}) (?<account>[A-Z0-9]{16})
36
+ tags: sepa
37
+ CZ:
38
+ parts: (?<iban_check>\d{2}) (?<bank>\d{4}) (?<branch>\d{6}) (?<account>\d{10})
39
+ tags: sepa
40
+ DE:
41
+ parts: (?<iban_check>\d{2}) (?<bank>\d{8}) (?<branch>\d{10})
42
+ tags: sepa
43
+ DK:
44
+ parts: (?<iban_check>\d{2}) (?<bank>\d{4}) (?<branch>\d{10})
45
+ tags: sepa
46
+ DO:
47
+ parts: (?<iban_check>\d{2}) (?<bank>[A-Z]{4}) (?<account>\d{20})
48
+ tags:
49
+ EE:
50
+ parts: (?<iban_check>\d{2}) (?<bank>\d{2}) (?<branch>\d{2}) (?<account>\d{11}) (?<check>\d)
51
+ tags: sepa
52
+ ES:
53
+ parts: (?<iban_check>\d{2}) (?<bank>\d{4}) (?<branch>\d{4}) (?<check>\d{2}) (?<account>\d{10})
54
+ tags: sepa
55
+ FI:
56
+ parts: (?<iban_check>\d{2}) (?<bank>\d{6}) (?<account>\d{7}) (?<check>\d)
57
+ tags: sepa
58
+ FO:
59
+ parts: (?<iban_check>\d{2}) (?<bank>\d{4}) (?<account>\d{9}) (?<check>\d)
60
+ tags:
61
+ FR:
62
+ parts: (?<iban_check>\d{2}) (?<bank>\d{5}) (?<branch>\d{5}) (?<account>[A-Z0-9]{11}) (?<check>\d{2})
63
+ tags: sepa
64
+ GB:
65
+ parts: (?<iban_check>\d{2}) (?<bank>[A-Z]{4}) (?<branch>\d{6}) (?<account>\d{8})
66
+ tags: sepa
67
+ GE:
68
+ parts: (?<iban_check>\d{2}) (?<bank>[A-Z]{2}) (?<account>\d{16})
69
+ tags:
70
+ GI:
71
+ parts: (?<iban_check>\d{2}) (?<bank>[A-Z]{4}) (?<account>[A-Z0-9]{15})
72
+ tags: sepa
73
+ GR:
74
+ parts: (?<iban_check>\d{2}) (?<bank>\d{3}) (?<branch>\d{4}) (?<account>[A-Z0-9]{16})
75
+ tags: sepa
76
+ GT:
77
+ parts: (?<iban_check>\d{2}) (?<bank>[A-Z0-9]{4}) [A-Z0-9]{2} [A-Z0-9]{2} (?<account>[A-Z0-9]{16})
78
+ tags:
79
+ HR:
80
+ parts: (?<iban_check>\d{2}) (?<bank>\d{7}) (?<account>\d{10})
81
+ tags: sepa
82
+ HU:
83
+ parts: (?<iban_check>\d{2}) (?<bank>\d{3}) (?<branch>\d{4}) (?<check>\d) (?<account>\d{15}) (?<check2>\d)
84
+ tags: sepa
85
+ IE:
86
+ parts: (?<iban_check>\d{2}) (?<bank>[A-Z]{4}) (?<branch>\d{6}) (?<account>\d{8})
87
+ tags: sepa
88
+ IL:
89
+ parts: (?<iban_check>\d{2}) (?<bank>\d{3}) (?<branch>\d{3}) (?<account>\d{13})
90
+ tags:
91
+ IS:
92
+ parts: (?<iban_check>\d{2}) (?<bank>\d{4}) (?<branch>\d{2}) (?<account>\d{16})
93
+ tags: sepa
94
+ IT:
95
+ parts: (?<iban_check>\d{2}) (?<check>[A-Z]) (?<bank>\d{5}) (?<branch>\d{5}) (?<account>[A-Z0-9]{12})
96
+ tags: sepa
97
+ KW:
98
+ parts: (?<iban_check>\d{2}) (?<bank>[A-Z]{4}) (?<account>\d{22})
99
+ tags:
100
+ KZ:
101
+ parts: (?<iban_check>\d{2}) (?<bank>\d{3}) (?<account>[A-Z0-9]{13})
102
+ tags:
103
+ LB:
104
+ parts: (?<iban_check>\d{2}) (?<bank>\d{4}) (?<account>[A-Z0-9]{20})
105
+ tags:
106
+ LI:
107
+ parts: (?<iban_check>\d{2}) (?<bank>\d{5}) (?<account>[A-Z0-9]{12})
108
+ tags: sepa
109
+ LT:
110
+ parts: (?<iban_check>\d{2}) (?<bank>\d{5}) (?<account>\d{11})
111
+ tags: sepa
112
+ LU:
113
+ parts: (?<iban_check>\d{2}) (?<bank>\d{3}) (?<account>[A-Z0-9]{13})
114
+ tags: sepa
115
+ LV:
116
+ parts: (?<iban_check>\d{2}) (?<bank>[A-Z]{4}) (?<account>[A-Z0-9]{13})
117
+ tags: sepa
118
+ MC:
119
+ parts: (?<iban_check>\d{2}) (?<bank>\d{5}) (?<branch>\d{5}) (?<account>[A-Z0-9]{11}) (?<check>\d{2})
120
+ tags: sepa
121
+ MD:
122
+ parts: (?<iban_check>\d{2}) (?<bank>\d{2}) (?<account>[A-Z0-9]{18})
123
+ tags:
124
+ ME:
125
+ parts: (?<iban_check>\d{2}) (?<bank>\d{3}) (?<account>\d{12}) (?<check>\d{2})
126
+ tags:
127
+ MK:
128
+ parts: (?<iban_check>\d{2}) (?<bank>\d{3}) (?<account>[A-Z0-9]{10}) (?<check>\d{2})
129
+ tags:
130
+ MR:
131
+ parts: (?<iban_check>\d{2}) (?<bank>\d{5}) (?<branch>\d{5}) (?<account>\d{11}) (?<check>\d{2})
132
+ tags:
133
+ MT:
134
+ parts: (?<iban_check>\d{2}) (?<bank>[A-Z]{4}) (?<branch>\d{5}) (?<account>[A-Z0-9]{18})
135
+ tags: sepa
136
+ MU:
137
+ parts: (?<iban_check>\d{2}) (?<bank>[A-Z]{4}\d{2}) (?<branch>\d{2}) (?<account>\d{12}) 000[A-Z]{3}
138
+ tags:
139
+ NL:
140
+ parts: (?<iban_check>\d{2}) (?<bank>[A-Z]{4}) (?<account>\d{10})
141
+ tags: sepa
142
+ NO:
143
+ parts: (?<iban_check>\d{2}) (?<bank>\d{4}) (?<account>\d{6}) (?<check>\d)
144
+ tags: sepa
145
+ PK:
146
+ parts: (?<iban_check>\d{2}) (?<bank>[A-Z]{4}) (?<account>[A-Z0-9]{16})
147
+ tags:
148
+ PL:
149
+ parts: (?<iban_check>\d{2}) (?<bank>\d{3}) (?<branch>\d{4}) (?<check>\d) (?<account>\d{16})
150
+ tags: sepa
151
+ PS:
152
+ parts: (?<iban_check>\d{2}) (?<bank>[A-Z0-9]{4}) \d{9} (?<account>\d{12})
153
+ tags:
154
+ PT:
155
+ parts: (?<iban_check>50) (?<bank>\d{4}) (?<branch>\d{4}) (?<account>\d{11}) (?<check>\d{2})
156
+ tags: sepa
157
+ RO:
158
+ parts: (?<iban_check>\d{2}) (?<bank>[A-Z]{4}) (?<account>[A-Z0-9]{16})
159
+ tags: sepa
160
+ RS:
161
+ parts: (?<iban_check>35) (?<bank>\d{3}) (?<account>\d{13}) (?<check>\d{2})
162
+ tags:
163
+ SE:
164
+ parts: (?<iban_check>\d{2}) (?<bank>\d{3}) (?<account>\d{17})
165
+ tags: sepa
166
+ SI:
167
+ parts: (?<iban_check>56) (?<bank>\d{2}) (?<branch>\d{3}) (?<account>\d{8}) (?<check>\d{2})
168
+ tags: sepa
169
+ SK:
170
+ parts: (?<iban_check>\d{2}) (?<bank>\d{4}) (?<branch>\d{6}) (?<account>\d{10})
171
+ tags: sepa
172
+ SM:
173
+ parts: (?<iban_check>\d{2}) (?<check>[A-Z]) (?<bank>\d{5}) (?<branch>\d{5}) (?<account>[A-Z0-9]{12})
174
+ tags: sepa
175
+ TN:
176
+ parts: (?<iban_check>59) (?<bank>\d{2}) (?<branch>\d{3}) (?<account>\d{15})
177
+ tags:
178
+ TR:
179
+ parts: (?<iban_check>\d{2}) (?<bank>\d{5}) 0 (?<account>[A-Z0-9]{16})
180
+ tags: sepa
181
+ VG:
182
+ parts: (?<iban_check>\d{2}) (?<bank>[A-Z]{4}) (?<account>\d{16})
183
+ tags:
184
+ XK:
185
+ parts: (?<iban_check>\d{2}) (?<bank>\d{4}) (?<account>\d{12})
186
+ tags:
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_model/validations"
4
+ require "iban_bic"
5
+
6
+ # ActiveModel Rails module.
7
+ module ActiveModel
8
+ # ActiveModel::Validations Rails module. Contains all the default validators.
9
+ module Validations
10
+ class IbanValidator < ActiveModel::EachValidator
11
+ def validate_each(record, attribute, value)
12
+ if !IbanBic.parse(value)
13
+ record.errors.add(attribute, :invalid_format)
14
+ elsif !IbanBic.valid_check?(value)
15
+ record.errors.add(attribute, :invalid_check)
16
+ elsif !IbanBic.valid_country_check?(value)
17
+ record.errors.add(attribute, :invalid_country_check)
18
+ elsif options[:tags] && !IbanBic.has_tags?(value, options[:tags])
19
+ record.errors.add(attribute, :invalid_tag)
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,54 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "rails/generators"
4
+ require "rails/generators/active_record"
5
+
6
+ module IbanBic
7
+ # Installs Iban+Bic in a rails app.
8
+ class InstallGenerator < ::Rails::Generators::Base
9
+ include ::Rails::Generators::Migration
10
+
11
+ source_root File.expand_path("../templates", __FILE__)
12
+
13
+ class_option(
14
+ :with_static_bics,
15
+ type: :boolean,
16
+ default: false,
17
+ desc: "Don't create bics table, use static bics."
18
+ )
19
+
20
+ class_option(
21
+ :bics_table_name,
22
+ type: :string,
23
+ default: "bics",
24
+ desc: "BICs table name, `bics` by default."
25
+ )
26
+
27
+ desc "Generates an initializer file for configuring IbanBic." \
28
+ " Also can generate a migration to add a bics table."
29
+
30
+ def create_migration_file
31
+ migration_template "create_bics.rb.erb", File.join("db", "migrate", "create_bics.rb") unless options.with_static_bics?
32
+ end
33
+
34
+ def create_initializer
35
+ template "iban_bic.rb.erb", File.join("config", "initializers", "iban_bic.rb")
36
+ end
37
+
38
+ def self.next_migration_number(dirname)
39
+ ::ActiveRecord::Generators::Base.next_migration_number(dirname)
40
+ end
41
+
42
+ def migration_version
43
+ "[#{ActiveRecord::VERSION::MAJOR}.#{ActiveRecord::VERSION::MINOR}]"
44
+ end
45
+
46
+ def bics_table_name
47
+ options.bics_table_name
48
+ end
49
+
50
+ def static_bics?
51
+ options.with_static_bics?
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ # This migration creates the `<%= bics_table_name %>` table.
4
+ class CreateBics < ActiveRecord::Migration<%= migration_version %>
5
+ def change
6
+ create_table :<%= bics_table_name %> do |t|
7
+ t.string :country, null: false
8
+ t.string :bank_code, null: false
9
+ t.string :bic, null: false
10
+ end
11
+
12
+ add_index :<%= bics_table_name %>, [:country, :bank_code], unique: true
13
+ end
14
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ IbanBic.configure do |config|
4
+ config.bics_table_name = "<%= bics_table_name %>"
5
+ config.use_static_bics = <%= static_bics? %>
6
+
7
+ # add [country_code] do |parts|
8
+ # Here test that parts (bank, branch, account and/or check) satifies national checks
9
+ # end
10
+
11
+ # config.iban_meta_path = "path/iban_meta.yml"
12
+ # config.static_bics_path = "path/bics/"
13
+ end
data/lib/iban_bic.rb ADDED
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "yaml"
4
+ require "iban_bic/version"
5
+ require "iban_bic/configuration"
6
+ require "iban_bic/core"
7
+ require "iban_bic/engine" if defined?(Rails::Engine)
8
+ require "iban_bic/defaults"
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ module IbanBic
4
+ class Configuration
5
+ attr_accessor :iban_meta_path, :use_static_bics, :bics_table_name, :static_bics_path
6
+
7
+ def country_validators
8
+ @country_validators ||= {}
9
+ end
10
+
11
+ def add(country)
12
+ country_validators[country] = Proc.new
13
+ end
14
+
15
+ def static_bics?
16
+ use_static_bics
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,91 @@
1
+ # frozen_string_literal: true
2
+
3
+ module IbanBic
4
+ module_function
5
+
6
+ def configuration
7
+ @configuration ||= Configuration.new
8
+ end
9
+
10
+ def configure
11
+ configuration.instance_eval(&Proc.new)
12
+ end
13
+
14
+ def parse(iban)
15
+ parts = parser[iban[0..1]]&.match(iban)
16
+ parts ? ActiveSupport::HashWithIndifferentAccess[parts.names.zip(parts.captures)] : nil
17
+ end
18
+
19
+ def has_tags?(iban, searched_tags)
20
+ (tags[iban[0..1]] & searched_tags).any?
21
+ end
22
+
23
+ def calculate_check(iban)
24
+ 98 - "#{iban[4..-1]}#{iban[0..3]}".each_char.map do |char|
25
+ case char
26
+ when "0".."9" then char
27
+ when "A".."Z" then (char.ord - 55).to_s
28
+ else raise ArgumentError, "Invalid IBAN format"
29
+ end
30
+ end .join.to_i % 97
31
+ end
32
+
33
+ def valid_check?(iban)
34
+ calculate_check(iban) == 97
35
+ end
36
+
37
+ def valid_country_check?(iban)
38
+ parts = parse(iban)
39
+ validator = IbanBic.configuration.country_validators[parts[:country]]
40
+ validator.nil? || validator.call(parts)
41
+ end
42
+
43
+ def calculate_bic(iban)
44
+ country = iban[0..1]
45
+ parts = parse(iban)
46
+ return nil unless parts&.fetch(:bank, nil)
47
+
48
+ bics.dig(country, parts[:bank])
49
+ end
50
+
51
+ def clear_cache
52
+ @parser = @static_bics = @dynamic_bics = nil
53
+ end
54
+
55
+ def parser
56
+ @parser ||= Hash[
57
+ ::YAML.load_file(configuration.iban_meta_path).map do |country, meta|
58
+ [country, /^(?<country>#{country})#{meta["parts"].delete(" ")}$/]
59
+ end
60
+ ].freeze
61
+ end
62
+
63
+ def tags
64
+ @tags ||= Hash[
65
+ ::YAML.load_file(configuration.iban_meta_path).map do |country, meta|
66
+ [country, meta["tags"]&.split&.map(&:to_sym) || []]
67
+ end
68
+ ].freeze
69
+ end
70
+
71
+ def bics
72
+ configuration.static_bics? ? static_bics : dynamic_bics
73
+ end
74
+
75
+ def static_bics
76
+ @static_bics ||= Hash[Dir.glob(File.join(configuration.static_bics_path, "*.yml")).map do |file|
77
+ [File.basename(file).delete(".yml").upcase, YAML.load_file(file)]
78
+ end].freeze
79
+ end
80
+
81
+ def dynamic_bics
82
+ @dynamic_bics ||= begin
83
+ ret = {}
84
+ Bic.find_each do |bic|
85
+ ret[bic.country] = {} unless ret[bic.country]
86
+ ret[bic.country][bic.bank_code] = bic.bic
87
+ end
88
+ ret.freeze
89
+ end
90
+ end
91
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "iban_bic/validators/countries/es.rb"
4
+
5
+ IbanBic.configure do |config|
6
+ config.iban_meta_path = File.expand_path("../../data/iban_meta.yml", __dir__)
7
+ config.static_bics_path = File.expand_path("../../data/bics/", __dir__)
8
+
9
+ config.bics_table_name = "bics"
10
+ config.use_static_bics = false
11
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_model/validations/iban_validator"
4
+
5
+ module IbanBic
6
+ class Engine < ::Rails::Engine
7
+ paths["app/models"] << "lib/iban_bic/models"
8
+ end
9
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Bic < ActiveRecord::Base
4
+ self.table_name = IbanBic.configuration.bics_table_name
5
+
6
+ after_commit do
7
+ IbanBic.clear_cache
8
+ end
9
+ end
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ def __bic_validation_proc(digits)
4
+ ret = 11 - digits.chars.each_with_index.sum { |x, i| x.to_i * 2**i } % 11
5
+ ret < 10 ? ret : 11 - ret
6
+ end
7
+
8
+ IbanBic.configure do
9
+ add "ES" do |parts|
10
+ parts[:check] == "#{__bic_validation_proc("00#{parts[:bank]}#{parts[:branch]}")}#{__bic_validation_proc(parts[:account])}"
11
+ end
12
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module IbanBic
4
+ VERSION = "0.1.0"
5
+ end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ namespace :iban_bic do
4
+ desc "Load static data to the database"
5
+ task load_data: :environment do
6
+ print "Loading data.\n"
7
+ IbanBic.static_bics.each do |country, data|
8
+ print "Loading #{data.length} bank codes for country #{country}.\n"
9
+ data.each do |bank_code, bic|
10
+ Bic.find_or_create_by(country: country, bank_code: bank_code) do |new_bic|
11
+ new_bic.bic = bic
12
+ end
13
+ end
14
+ end
15
+ print "All data loaded.\n"
16
+ end
17
+ end
metadata ADDED
@@ -0,0 +1,159 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: iban_bic
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Leonardo Diez
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2017-10-04 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rails
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '5.1'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '5.1'
27
+ - !ruby/object:Gem::Dependency
28
+ name: codecov
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '0.1'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '0.1'
41
+ - !ruby/object:Gem::Dependency
42
+ name: generator_spec
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: 0.9.3
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: 0.9.3
55
+ - !ruby/object:Gem::Dependency
56
+ name: rubocop
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '0.50'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '0.50'
69
+ - !ruby/object:Gem::Dependency
70
+ name: rspec-rails
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '3.6'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '3.6'
83
+ - !ruby/object:Gem::Dependency
84
+ name: sqlite3
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: '1.3'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: '1.3'
97
+ - !ruby/object:Gem::Dependency
98
+ name: virtus
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - "~>"
102
+ - !ruby/object:Gem::Version
103
+ version: '1.0'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - "~>"
109
+ - !ruby/object:Gem::Version
110
+ version: '1.0'
111
+ description: When IBAN validation is not enough
112
+ email:
113
+ - leiodd@gmail.com
114
+ executables: []
115
+ extensions: []
116
+ extra_rdoc_files: []
117
+ files:
118
+ - README.md
119
+ - Rakefile
120
+ - data/bics/es.yml
121
+ - data/iban_meta.yml
122
+ - lib/active_model/validations/iban_validator.rb
123
+ - lib/generators/iban_bic/install_generator.rb
124
+ - lib/generators/iban_bic/templates/create_bics.rb.erb
125
+ - lib/generators/iban_bic/templates/iban_bic.rb.erb
126
+ - lib/iban_bic.rb
127
+ - lib/iban_bic/configuration.rb
128
+ - lib/iban_bic/core.rb
129
+ - lib/iban_bic/defaults.rb
130
+ - lib/iban_bic/engine.rb
131
+ - lib/iban_bic/models/bic.rb
132
+ - lib/iban_bic/validators/countries/es.rb
133
+ - lib/iban_bic/version.rb
134
+ - lib/tasks/load_data.rake
135
+ homepage: https://github.info/podemos-info/iban_bic
136
+ licenses:
137
+ - MIT
138
+ metadata: {}
139
+ post_install_message:
140
+ rdoc_options: []
141
+ require_paths:
142
+ - lib
143
+ required_ruby_version: !ruby/object:Gem::Requirement
144
+ requirements:
145
+ - - ">="
146
+ - !ruby/object:Gem::Version
147
+ version: '0'
148
+ required_rubygems_version: !ruby/object:Gem::Requirement
149
+ requirements:
150
+ - - ">="
151
+ - !ruby/object:Gem::Version
152
+ version: '0'
153
+ requirements: []
154
+ rubyforge_project:
155
+ rubygems_version: 2.6.12
156
+ signing_key:
157
+ specification_version: 4
158
+ summary: IBAN and BIC tools for Rails applications
159
+ test_files: []