iban_bic 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
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: []