valvat 1.1.4 → 1.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +0 -0
- data/.github/workflows/ruby.yml +3 -3
- data/.rubocop.yml +11 -2
- data/CHANGES.md +19 -2
- data/MIT-LICENSE +1 -1
- data/README.md +151 -80
- data/gemfiles/activemodel-6 +3 -0
- data/gemfiles/activemodel-7 +3 -0
- data/gemfiles/standalone +3 -0
- data/lib/active_model/validations/valvat_validator.rb +1 -1
- data/lib/valvat/checksum/es.rb +49 -16
- data/lib/valvat/checksum/fr.rb +1 -1
- data/lib/valvat/checksum/hr.rb +1 -1
- data/lib/valvat/checksum/hu.rb +1 -1
- data/lib/valvat/error.rb +16 -16
- data/lib/valvat/local.rb +2 -49
- data/lib/valvat/lookup/base.rb +73 -0
- data/lib/valvat/lookup/hmrc.rb +86 -0
- data/lib/valvat/lookup/vies.rb +98 -0
- data/lib/valvat/lookup.rb +16 -5
- data/lib/valvat/utils.rb +0 -1
- data/lib/valvat/version.rb +1 -1
- data/lib/valvat.rb +50 -4
- data/spec/spec_helper.rb +2 -1
- data/spec/valvat/checksum/es_spec.rb +48 -1
- data/spec/valvat/checksum/gb_spec.rb +1 -0
- data/spec/valvat/lookup/hmrc_spec.rb +32 -0
- data/spec/valvat/lookup/vies_spec.rb +23 -0
- data/spec/valvat/lookup_spec.rb +272 -80
- data/spec/valvat/utils_spec.rb +1 -1
- data/spec/valvat_spec.rb +12 -12
- data/valvat.gemspec +3 -2
- data.tar.gz.sig +0 -0
- metadata +24 -25
- metadata.gz.sig +0 -0
- data/lib/valvat/lookup/fault.rb +0 -38
- data/lib/valvat/lookup/request.rb +0 -57
- data/lib/valvat/lookup/response.rb +0 -37
- data/spec/valvat/lookup/fault_spec.rb +0 -34
- data/spec/valvat/lookup/request_spec.rb +0 -32
- data/spec/valvat/lookup/response_spec.rb +0 -29
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d8adbca62e2ebbf198c817bfed2cf8dc2d375a24cb146dff52ce42a6dd59750d
|
4
|
+
data.tar.gz: 84949112505cff60333ff382583b54f4b4c20cb86e59bf5cbb1c16616c1c3ce7
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d2c2cb07112932730644124d140dc29a8e1ffc2e0b590d67ef1ff9f24dfb9c327fc72c189a8ebccdb983c04271c5cabebfa210bc20a61d8b9788c489135d58f9
|
7
|
+
data.tar.gz: 543a2f012caac4dfb874d9c5cca697b3cde38bbb16ca646ff87e66020d913f58094890ceed95d0ffa39637d4c538253358fe0f6ae4ea0a045fe6de4fd9f8585b
|
checksums.yaml.gz.sig
CHANGED
Binary file
|
data/.github/workflows/ruby.yml
CHANGED
@@ -2,12 +2,12 @@ name: Specs
|
|
2
2
|
|
3
3
|
on:
|
4
4
|
push:
|
5
|
-
branches: [ master ]
|
6
5
|
paths-ignore:
|
7
6
|
- 'README.md'
|
8
7
|
- 'CHANGES.md'
|
9
8
|
pull_request:
|
10
|
-
|
9
|
+
schedule:
|
10
|
+
- cron: '52 8 * * *'
|
11
11
|
|
12
12
|
jobs:
|
13
13
|
test:
|
@@ -17,7 +17,7 @@ jobs:
|
|
17
17
|
BUNDLE_GEMFILE: gemfiles/${{ matrix.gemfile }}
|
18
18
|
strategy:
|
19
19
|
matrix:
|
20
|
-
ruby-version: ['2.6', '2.7', '3.0', '3.1', '
|
20
|
+
ruby-version: ['2.6', '2.7', '3.0', '3.1', 'jruby-9.3.2.0']
|
21
21
|
gemfile: [ 'standalone', 'activemodel-5', 'activemodel-6', 'activemodel-7' ]
|
22
22
|
exclude:
|
23
23
|
- ruby-version: '3.0'
|
data/.rubocop.yml
CHANGED
@@ -9,7 +9,16 @@ Metrics/BlockLength:
|
|
9
9
|
- spec/**/*_spec.rb
|
10
10
|
|
11
11
|
Style/Documentation:
|
12
|
-
|
12
|
+
Enabled: false
|
13
13
|
|
14
14
|
RSpec/MultipleExpectations:
|
15
|
-
|
15
|
+
Enabled: false
|
16
|
+
|
17
|
+
Style/StringChars:
|
18
|
+
Enabled: false
|
19
|
+
|
20
|
+
RSpec/NestedGroups:
|
21
|
+
Max: 4
|
22
|
+
|
23
|
+
RSpec/ExampleLength:
|
24
|
+
Enabled: false
|
data/CHANGES.md
CHANGED
@@ -1,7 +1,24 @@
|
|
1
1
|
|
2
2
|
### dev
|
3
3
|
|
4
|
-
[full changelog](http://github.com/yolk/valvat/compare/v1.
|
4
|
+
[full changelog](http://github.com/yolk/valvat/compare/v1.2.0...master)
|
5
|
+
|
6
|
+
### 1.2.0 / 2022-09-30
|
7
|
+
|
8
|
+
[full changelog](http://github.com/yolk/valvat/compare/v1.1.5...v1.2.0)
|
9
|
+
|
10
|
+
* Implemented lookup of VAT numbers from the UK (via HMRC api and only with :uk option set to true) (by [Adrien Rey-Jarthon](https://github.com/jarthod))
|
11
|
+
* Remimplemented VIES lookup using only nethttp (removes dependency on savon)
|
12
|
+
* Deprecate require 'valvat/local'. Please require 'valvat' directly.
|
13
|
+
* Apply more rules to spanish VAT numbers on checksum validation #115 (by [Thomas Scalise](https://github.com/KirtashW17))
|
14
|
+
|
15
|
+
### 1.1.5 / 2022-09-14
|
16
|
+
|
17
|
+
[full changelog](http://github.com/yolk/valvat/compare/v1.1.4...v1.1.5)
|
18
|
+
|
19
|
+
* Fixed natural person VAT checksum validation for ES #114 (by [Thomas Scalise](https://github.com/KirtashW17))
|
20
|
+
* Better (ruby) code blocks in README #113
|
21
|
+
* Minor internal syntax changes / refactorings
|
5
22
|
|
6
23
|
### 1.1.4 / 2022-05-05
|
7
24
|
|
@@ -14,7 +31,7 @@
|
|
14
31
|
|
15
32
|
[full changelog](http://github.com/yolk/valvat/compare/v1.1.2...v1.1.3)
|
16
33
|
|
17
|
-
* Handle Savon::HTTPError and Savon::UnknownOperationError as
|
34
|
+
* Handle Savon::HTTPError and Savon::UnknownOperationError as LookupError and throw Valvat::HTTPError and Valvat::OperationUnknown instead.
|
18
35
|
|
19
36
|
### 1.1.2 / 2021-10-29
|
20
37
|
|
data/MIT-LICENSE
CHANGED
data/README.md
CHANGED
@@ -7,7 +7,7 @@ Validates european vat numbers. Standalone or as a ActiveModel validator.
|
|
7
7
|
|
8
8
|
## A note on Brexit
|
9
9
|
|
10
|
-
Valvat supports validating VAT-IDs from the UK by syntax
|
10
|
+
Valvat supports validating VAT-IDs from the UK by syntax, checksum and using the HMRC API (for backwards compatibility only with the `:uk` option set to true). Validation against the VIES web service stopped working early 2021.
|
11
11
|
|
12
12
|
Northern Ireland received its own VAT number prefix - XI which is supported by VIES web service so any XI-prefixed VAT numbers should be validated as any EU VAT number.
|
13
13
|
|
@@ -15,24 +15,24 @@ Northern Ireland received its own VAT number prefix - XI which is supported by V
|
|
15
15
|
|
16
16
|
* Simple syntax verification
|
17
17
|
* Lookup via the VIES web service
|
18
|
+
* (Optional) lookup via the HMRC web service (for UK VAT numbers)
|
18
19
|
* ActiveModel/Rails integration
|
19
20
|
* Works standalone without ActiveModel
|
21
|
+
* No runtime dependencies
|
20
22
|
* I18n locales for language specific error messages in English, German, French, Spanish, Italian, Portuguese, Polish, Swedish, Dutch, Danish, Czech, Slovakian, Hungarian, Bulgarian, Romanian, Latvian, Catalan, Norwegian, and Finnish.
|
21
23
|
* *Experimental* checksum verification
|
22
24
|
|
23
|
-
valvat is tested and works with ruby MRI 2.6/2.7/3.0/3.1, jruby
|
25
|
+
valvat is tested and works with ruby MRI 2.6/2.7/3.0/3.1, jruby and ActiveModel 5/6/7. If you need support for ruby down to 1.9.3 and ActiveModel 3 and 4 use [v1.0.1](https://github.com/yolk/valvat/tree/v1.0.1).
|
24
26
|
|
25
27
|
## Installation
|
26
28
|
|
27
29
|
Add it to your Gemfile:
|
28
30
|
|
29
|
-
|
31
|
+
```ruby
|
32
|
+
gem 'valvat'
|
33
|
+
```
|
30
34
|
|
31
|
-
|
32
|
-
|
33
|
-
gem 'valvat', require: 'valvat/local'
|
34
|
-
|
35
|
-
In any case run:
|
35
|
+
And run:
|
36
36
|
|
37
37
|
$ bundle
|
38
38
|
|
@@ -44,66 +44,96 @@ Or install it yourself as:
|
|
44
44
|
|
45
45
|
To verify the syntax of a vat number:
|
46
46
|
|
47
|
-
|
48
|
-
|
47
|
+
```ruby
|
48
|
+
Valvat.new("DE345789003").valid?
|
49
|
+
# => true or false
|
50
|
+
```
|
49
51
|
|
50
52
|
It is also possible to bypass initializing a Valvat instance and check the syntax of a vat number string directly with:
|
51
53
|
|
52
|
-
|
53
|
-
|
54
|
+
```ruby
|
55
|
+
Valvat::Syntax.validate("DE345789003")
|
56
|
+
# => true or false
|
57
|
+
```
|
58
|
+
|
59
|
+
## Validate against the VIES / HMRC web service
|
54
60
|
|
55
|
-
|
61
|
+
To check if the given vat number exists via the VIES or HMRC web service:
|
56
62
|
|
57
|
-
|
63
|
+
```ruby
|
64
|
+
Valvat.new("DE345789003").exists?
|
65
|
+
# => true or false or nil
|
66
|
+
```
|
58
67
|
|
59
|
-
|
60
|
-
=> true or false or nil
|
68
|
+
Or to lookup a vat number string directly:
|
61
69
|
|
62
|
-
|
70
|
+
```ruby
|
71
|
+
Valvat::Lookup.validate("DE345789003")
|
72
|
+
# => true or false or nil
|
73
|
+
```
|
63
74
|
|
64
|
-
|
65
|
-
=> true or false or nil
|
75
|
+
To keep backwards compatibility lookups of UK VAT numbers against the HMRC API are only performed with the option `:uk` set to true.
|
66
76
|
|
67
|
-
|
77
|
+
```ruby
|
78
|
+
Valvat::Lookup.validate("GB553557881", uk: true)
|
79
|
+
# => true or false or nil
|
80
|
+
```
|
81
|
+
|
82
|
+
Without this option the lookup of UK VAT number always returns `false`.
|
83
|
+
|
84
|
+
*IMPORTANT* Keep in mind that the web service might be offline at some time for all or some member states. If this happens `exists?` or `Valvat::Lookup.validate` will return `nil`. See *Handling of maintenance errors* for further details.
|
68
85
|
|
69
86
|
### Details & request identifier
|
70
87
|
|
71
88
|
If you need all details and not only if the VAT is valid, pass {detail: true} as second parameter to the lookup call.
|
72
89
|
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
90
|
+
```ruby
|
91
|
+
Valvat.new("IE6388047V").exists?(detail: true)
|
92
|
+
=> {
|
93
|
+
:country_code=> "IE", :vat_number => "6388047V", :valid => true,
|
94
|
+
:request_date => Date.today, :name=> "GOOGLE IRELAND LIMITED",
|
95
|
+
:address=> "1ST & 2ND FLOOR ,GORDON HOUSE ,BARROW STREET ,DUBLIN 4"
|
96
|
+
} or false or nil
|
97
|
+
```
|
79
98
|
|
80
|
-
According to EU law, or at least as Austria sees it, it's mandatory to verify the VAT number of every new customer, but also to check the VAT number periodicaly. To prove that you have checked the VAT number, the
|
99
|
+
According to EU law, or at least as Austria sees it, it's mandatory to verify the VAT number of every new customer, but also to check the VAT number periodicaly. To prove that you have checked the VAT number, the web service can return a `request_identifier`.
|
81
100
|
|
82
101
|
To receive a `request_identifier` you need to pass your own VAT number in the options hash. In this example, Google (VAT IE6388047V) is checking the validity of eBays VAT number (LU21416127)
|
83
102
|
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
103
|
+
```ruby
|
104
|
+
Valvat.new("LU21416127").exists?(requester: "IE6388047V")
|
105
|
+
=> {
|
106
|
+
:country_code=>"LU", :vat_number => "21416127", :valid => true,
|
107
|
+
:request_date => Date.today, :name=>"EBAY EUROPE S.A R.L.",
|
108
|
+
:address => "22, BOULEVARD ROYAL\nL-2449 LUXEMBOURG",
|
109
|
+
:company_type => nil, :request_identifier => "some_uniq_string"
|
110
|
+
} or false or nil
|
111
|
+
```
|
91
112
|
|
92
113
|
If the given `requester` is invalid, a `Valvat::InvalidRequester` error is thrown.
|
93
114
|
|
94
|
-
|
115
|
+
When requesting a `request_identifier` for a GB VAT number, the requester must be your own GB number; a EU VAT number won't work.
|
116
|
+
|
117
|
+
Note that when validating UK VAT numbers using the HMRC service, the detail output is modified to match the one from VIES more closely with slight differences remaining:
|
118
|
+
|
119
|
+
1. The `request_date` will actually be a (more precise) `Time` instead of a `Date`
|
120
|
+
2. The `address` string will join lines using `\n` instead of `,` so it's more acurate and can be displayed nicely.
|
121
|
+
|
122
|
+
### Handling of maintenance errors
|
95
123
|
|
96
124
|
From time to time the VIES web service for one or all member states is down for maintenance. To handle this kind of temporary errors, `Valvat::Lookup#validate` returns `nil` by default to indicate that there is no way at the moment to say if the given VAT is valid or not. You should revalidate the VAT later. If you prefer an error, use the `raise_error` option:
|
97
125
|
|
98
|
-
|
126
|
+
```ruby
|
127
|
+
Valvat.new("IE6388047V").exists?(raise_error: true)
|
128
|
+
```
|
99
129
|
|
100
130
|
This raises `Valvat::ServiceUnavailable` or `Valvat::MemberStateUnavailable` instead of returning `nil`.
|
101
131
|
|
102
132
|
Visit [http://ec.europa.eu/taxation_customs/vies/viesspec.do](http://ec.europa.eu/taxation_customs/vies/viesspec.do) for more accurate information at what time the service for a specific member state will be down.
|
103
133
|
|
104
|
-
### Handling of other
|
134
|
+
### Handling of other errors
|
105
135
|
|
106
|
-
All other errors accuring while validating against the
|
136
|
+
All other errors accuring while validating against the web service are raised and must be handled by you. These include:
|
107
137
|
|
108
138
|
* `Valvat::InvalidRequester`
|
109
139
|
* `Valvat::BlockedError`
|
@@ -113,39 +143,45 @@ All other errors accuring while validating against the VIES web service are rais
|
|
113
143
|
|
114
144
|
If you want to suppress all known error cases. Pass in the `raise_error` option set to `false`:
|
115
145
|
|
116
|
-
|
146
|
+
```ruby
|
147
|
+
Valvat.new("IE6388047V").exists?(raise_error: false)
|
148
|
+
```
|
117
149
|
|
118
150
|
This will return `nil` instead of raising a known error.
|
119
151
|
|
120
|
-
### Set options for the
|
121
|
-
|
122
|
-
Use the `:savon` key to set options for the used savon SOAP client. For example to log all requests:
|
152
|
+
### Set options for the Net::HTTP client
|
123
153
|
|
124
|
-
|
154
|
+
Use the `:http` key to set options for the http client. These options are directly passed to `Net::HTTP.start`.
|
125
155
|
|
126
|
-
|
156
|
+
For example to set timeouts:
|
127
157
|
|
128
|
-
|
158
|
+
```ruby
|
159
|
+
Valvat.new("IE6388047V").exists?(http: { open_timeout: 10, read_timeout: 10 })
|
160
|
+
```
|
129
161
|
|
130
162
|
### Skip local validation before lookup
|
131
163
|
|
132
|
-
To prevent unnecessary requests, valvat performs a local syntax check before making the request to the
|
164
|
+
To prevent unnecessary requests, valvat performs a local syntax check before making the request to the web service. If you want to skip this step (for any reason), set the `:skip_local_validation` option to `true`.
|
133
165
|
|
134
166
|
## Experimental checksum verification
|
135
167
|
|
136
168
|
valvat allows to check vat numbers from AT, BE, BG, DE, DK, ES, FR, FI, GR, IE, IT, LU, NL, PL, PT, SE and SI against a checksum calculation. All other member states will fall back to a basic syntax check:
|
137
169
|
|
138
|
-
|
139
|
-
|
170
|
+
```ruby
|
171
|
+
Valvat.new("DE345789003").valid_checksum?
|
172
|
+
# => true or false
|
173
|
+
```
|
140
174
|
|
141
|
-
These results are more valuable than a simple syntax check, but keep in mind: they can not replace a lookup via VIES.
|
175
|
+
These results are more valuable than a simple syntax check, but keep in mind: they can not replace a lookup via VIES or HMRC.
|
142
176
|
|
143
177
|
*IMPORTANT* This feature was tested against all vat numbers I could get my hand on, but it is still marked as *experimental* because these calculations are not documented and may return wrong results.
|
144
178
|
|
145
179
|
To bypass initializing a Valvat instance:
|
146
180
|
|
147
|
-
|
148
|
-
|
181
|
+
```ruby
|
182
|
+
Valvat::Checksum.validate("DE345789003")
|
183
|
+
# => true or false
|
184
|
+
```
|
149
185
|
|
150
186
|
## Usage with ActiveModel / Rails
|
151
187
|
|
@@ -153,7 +189,9 @@ To bypass initializing a Valvat instance:
|
|
153
189
|
|
154
190
|
When the valvat gem is required and ActiveModel is already loaded, everything will work fine out of the box. If your load order differs just add
|
155
191
|
|
156
|
-
|
192
|
+
```ruby
|
193
|
+
require 'active_model/validations/valvat_validator'
|
194
|
+
```
|
157
195
|
|
158
196
|
after ActiveModel has been loaded.
|
159
197
|
|
@@ -161,35 +199,53 @@ after ActiveModel has been loaded.
|
|
161
199
|
|
162
200
|
To validate the attribute `vat_number` add this to your model:
|
163
201
|
|
164
|
-
|
165
|
-
|
166
|
-
|
202
|
+
```ruby
|
203
|
+
class MyModel < ActiveRecord::Base
|
204
|
+
validates :vat_number, valvat: true
|
205
|
+
end
|
206
|
+
```
|
167
207
|
|
168
208
|
### Additional lookup validation
|
169
209
|
|
170
|
-
To additionally perform
|
210
|
+
To additionally perform an lookup via VIES:
|
211
|
+
|
212
|
+
```ruby
|
213
|
+
validates :vat_number, valvat: { lookup: true }
|
214
|
+
```
|
215
|
+
|
216
|
+
To also perform an lookup via HMRC for UK VAT numbers:
|
171
217
|
|
172
|
-
|
218
|
+
```ruby
|
219
|
+
validates :vat_number, valvat: { lookup: { uk: true } }
|
220
|
+
```
|
173
221
|
|
174
|
-
By default this will validate to true if the
|
222
|
+
By default this will validate to true if the web service is down. To fail in this case simply add the `:fail_if_down` option:
|
175
223
|
|
176
|
-
|
224
|
+
```ruby
|
225
|
+
validates :vat_number, valvat: { lookup: { fail_if_down: true } }
|
226
|
+
```
|
177
227
|
|
178
228
|
You can pass in any options accepted by `Valvat::Lookup#validate`:
|
179
229
|
|
180
|
-
|
230
|
+
```ruby
|
231
|
+
validates :vat_number, valvat: { lookup: { raise_error: true, http: { read_timeout: 12 } } }
|
232
|
+
```
|
181
233
|
|
182
234
|
### Additional (and experimental) checksum validation
|
183
235
|
|
184
236
|
To additionally perform a checksum validation:
|
185
237
|
|
186
|
-
|
238
|
+
```ruby
|
239
|
+
validates :vat_number, valvat: { checksum: true }
|
240
|
+
```
|
187
241
|
|
188
242
|
### Additional ISO country code validation
|
189
243
|
|
190
244
|
If you want the vat number’s (ISO) country to match another country attribute, use the _match_country_ option:
|
191
245
|
|
192
|
-
|
246
|
+
```ruby
|
247
|
+
validates :vat_number, valvat: { match_country: :country }
|
248
|
+
```
|
193
249
|
|
194
250
|
where it is supposed that your model has a method named _country_ which returns the country ISO code you want to match.
|
195
251
|
|
@@ -197,48 +253,62 @@ where it is supposed that your model has a method named _country_ which returns
|
|
197
253
|
|
198
254
|
By default blank vat numbers validate to false. To change this add the `:allow_blank` option:
|
199
255
|
|
200
|
-
|
256
|
+
```ruby
|
257
|
+
validates :vat_number, valvat: { allow_blank: true }
|
258
|
+
```
|
201
259
|
|
202
260
|
### Allow vat numbers outside of europe
|
203
261
|
|
204
262
|
To allow vat numbers from outside of europe, add something like this to your model (country_code should return a upcase ISO country code):
|
205
263
|
|
206
|
-
|
207
|
-
|
264
|
+
```ruby
|
265
|
+
class MyModel < ActiveRecord::Base
|
266
|
+
validates :vat_number, valvat: true, if: :eu?
|
208
267
|
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
268
|
+
def eu?
|
269
|
+
Valvat::Utils::EU_MEMBER_STATES.include?(country_code)
|
270
|
+
end
|
271
|
+
end
|
272
|
+
```
|
213
273
|
|
214
274
|
## Utilities
|
215
275
|
|
216
276
|
To split a vat number into the country code and the remaining chars:
|
217
277
|
|
218
|
-
|
219
|
-
|
278
|
+
```ruby
|
279
|
+
Valvat::Utils.split("ATU345789003")
|
280
|
+
# => ["AT", "U345789003"]
|
281
|
+
```
|
220
282
|
|
221
283
|
or
|
222
284
|
|
223
|
-
|
224
|
-
|
285
|
+
```ruby
|
286
|
+
Valvat.new("ATU345789003").to_a
|
287
|
+
# => ["AT", "U345789003"]
|
288
|
+
```
|
225
289
|
|
226
290
|
Both methods always return an array. If it can not detect the country or the given country is located outside of europe it returns `[nil, nil]`. Please note that this does not strictly return the ISO country code: for greek vat numbers this returns the ISO language code 'EL' instead of the ISO country code 'GR'.
|
227
291
|
|
228
292
|
To extract the ISO country code of a given vat number:
|
229
293
|
|
230
|
-
|
231
|
-
|
294
|
+
```ruby
|
295
|
+
Valvat.new("EL7345789003").iso_country_code
|
296
|
+
# => "GR"
|
297
|
+
```
|
232
298
|
|
233
299
|
To extract the vat country code (first two chars in every european vat number):
|
234
300
|
|
235
|
-
|
236
|
-
|
301
|
+
```ruby
|
302
|
+
Valvat.new("EL7345789003").vat_country_code
|
303
|
+
# => "EL"
|
304
|
+
```
|
237
305
|
|
238
306
|
To normalize a vat number:
|
239
307
|
|
240
|
-
|
241
|
-
|
308
|
+
```ruby
|
309
|
+
Valvat::Utils.normalize("atu345789003")
|
310
|
+
# => "ATU345789003"
|
311
|
+
```
|
242
312
|
|
243
313
|
This basically just removes trailing spaces and ensures all chars are uppercase.
|
244
314
|
|
@@ -249,6 +319,7 @@ There seems to be a problem when using the VIES service over IPv6. Sadly this is
|
|
249
319
|
## Links
|
250
320
|
|
251
321
|
* [VIES web service](http://ec.europa.eu/taxation_customs/vies)
|
322
|
+
* [HMRC web service](https://developer.service.hmrc.gov.uk/api-documentation/docs/api/service/vat-registered-companies-api/1.0)
|
252
323
|
* [European vat number formats (german)](http://bzst.de/DE/Steuern_International/USt_Identifikationsnummer/Merkblaetter/Aufbau_USt_IdNr.html)
|
253
324
|
* [European vat number formats on Wikipedia](http://en.wikipedia.org/wiki/European_Union_Value_Added_Tax)
|
254
325
|
|
@@ -258,7 +329,7 @@ https://github.com/yolk/valvat/graphs/contributors
|
|
258
329
|
|
259
330
|
## BlaBla
|
260
331
|
|
261
|
-
Copyright (c) 2011-2022
|
332
|
+
Copyright (c) 2011-2022 mite GmbH
|
262
333
|
|
263
334
|
Beyond that, the implementation is licensed under the MIT License.
|
264
335
|
|
data/gemfiles/activemodel-6
CHANGED
data/gemfiles/activemodel-7
CHANGED
data/gemfiles/standalone
CHANGED
@@ -74,7 +74,7 @@ module ActiveModel
|
|
74
74
|
message: options[:message],
|
75
75
|
country_adjective: I18n.translate(
|
76
76
|
:"valvat.country_adjectives.#{iso_country_code.downcase}",
|
77
|
-
default: [:
|
77
|
+
default: [:'valvat.country_adjectives.eu', 'european']
|
78
78
|
))
|
79
79
|
end
|
80
80
|
|
data/lib/valvat/checksum/es.rb
CHANGED
@@ -4,32 +4,53 @@ class Valvat
|
|
4
4
|
module Checksum
|
5
5
|
class ES < Base
|
6
6
|
NATURAL_PERSON_CHARS = %w[T R W A G M Y F P D X B N J Z S Q V H L C K E].freeze
|
7
|
-
NATURAL_PERSON_EXP = /\A
|
7
|
+
NATURAL_PERSON_EXP = /\A[KLMXYZ\d]/.freeze
|
8
8
|
LEGAL_PERSON_CHARS = [false] + %w[A B C D E F G H I J]
|
9
|
-
LEGAL_PERSON_EXP = /\A[NPQRSW]\d{7}[ABCDEFGHIJ]\Z/.freeze
|
10
9
|
NIE_DIGIT_BY_LETTER = %w[X Y Z].freeze
|
10
|
+
GIVEN_CD_IS_A_LETTER_EXP = /[A-Z]\Z/.freeze
|
11
|
+
LEGAL_PERSON_EXP = /\A[ABCDEFGHJUVNPQRSW]/.freeze
|
12
|
+
CIF_MUST_BE_A_LETTER_EXP = /\A[NPQRSW]/.freeze
|
13
|
+
CIF_MUST_BE_A_NUMBER_EXP = /\A[HJUV]/.freeze
|
14
|
+
SPECIAL_NIF_EXP = /\A[KLM]/.freeze
|
11
15
|
|
12
|
-
def
|
13
|
-
|
16
|
+
def validate
|
17
|
+
passes_special_validations? && possible_check_digits.include?(given_check_digit)
|
14
18
|
end
|
15
19
|
|
16
|
-
|
20
|
+
private
|
21
|
+
|
22
|
+
def passes_special_validations?
|
23
|
+
!(
|
24
|
+
# [KLM]: CD first two numerical digits must be between 01 and 56 (both inclusive)
|
25
|
+
(vat.to_s_wo_country =~ SPECIAL_NIF_EXP &&
|
26
|
+
vat.to_s_wo_country[1..2].to_i > 56) or vat.to_s_wo_country[1..2].to_i < 0o1 ||
|
27
|
+
# Exceptions: X0000000T, 00000001R, 00000000T, 99999999R are invalid.
|
28
|
+
%w[X0000000T 00000001R 00000000T 99999999R].include?(vat.to_s_wo_country)
|
29
|
+
)
|
30
|
+
end
|
31
|
+
|
32
|
+
def given_check_digit
|
33
|
+
given_cd_is_a_letter? ? str_wo_country[-1] : super
|
34
|
+
end
|
35
|
+
|
36
|
+
def possible_check_digits
|
37
|
+
natural_person? ? possible_cd_natural_person : possible_cds_legal_person
|
38
|
+
end
|
39
|
+
|
40
|
+
def possible_cd_natural_person
|
17
41
|
letter = vat.to_s_wo_country[0]
|
18
42
|
nie_digit = NIE_DIGIT_BY_LETTER.index(letter)
|
19
|
-
NATURAL_PERSON_CHARS["#{nie_digit}#{figures_str}".to_i.modulo(23)]
|
43
|
+
[NATURAL_PERSON_CHARS["#{nie_digit}#{figures_str}".to_i.modulo(23)]]
|
20
44
|
end
|
21
45
|
|
22
|
-
def
|
46
|
+
def possible_cds_legal_person
|
23
47
|
chk = 10 - sum_of_figures_for_at_es_it_se(reverse_ints: true).modulo(10)
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
(chk == 10 ? 0 : chk)
|
48
|
+
possible_check_digits = []
|
49
|
+
possible_check_digits << LEGAL_PERSON_CHARS[chk] if cd_can_be_a_letter?
|
50
|
+
if cd_can_be_a_num?
|
51
|
+
possible_check_digits << (chk == 10 ? 0 : chk)
|
28
52
|
end
|
29
|
-
|
30
|
-
|
31
|
-
def given_check_digit
|
32
|
-
person? ? str_wo_country[-1] : super
|
53
|
+
possible_check_digits
|
33
54
|
end
|
34
55
|
|
35
56
|
def str_wo_country
|
@@ -46,7 +67,19 @@ class Valvat
|
|
46
67
|
end
|
47
68
|
|
48
69
|
def legal_foreign_person?
|
49
|
-
!!(vat.to_s_wo_country =~
|
70
|
+
!!(vat.to_s_wo_country =~ FOREIGN_LEGAL_PERSON_EXP)
|
71
|
+
end
|
72
|
+
|
73
|
+
def cd_can_be_a_letter?
|
74
|
+
vat.to_s_wo_country !~ CIF_MUST_BE_A_NUMBER_EXP
|
75
|
+
end
|
76
|
+
|
77
|
+
def cd_can_be_a_num?
|
78
|
+
vat.to_s_wo_country !~ CIF_MUST_BE_A_LETTER_EXP
|
79
|
+
end
|
80
|
+
|
81
|
+
def given_cd_is_a_letter?
|
82
|
+
!!(vat.to_s_wo_country =~ GIVEN_CD_IS_A_LETTER_EXP)
|
50
83
|
end
|
51
84
|
end
|
52
85
|
end
|
data/lib/valvat/checksum/fr.rb
CHANGED
data/lib/valvat/checksum/hr.rb
CHANGED