valvat 0.5.0 → 0.6.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 +4 -4
- data/.travis.yml +8 -0
- data/CHANGES.md +11 -1
- data/README.md +13 -7
- data/gemfiles/activemodel-3-2 +8 -0
- data/gemfiles/activemodel-4 +8 -0
- data/gemfiles/standalone +7 -0
- data/lib/active_model/validations/valvat_validator.rb +54 -0
- data/lib/valvat.rb +1 -1
- data/lib/valvat/checksum.rb +24 -3
- data/lib/valvat/checksum/at.rb +1 -3
- data/lib/valvat/checksum/bg.rb +10 -10
- data/lib/valvat/checksum/es.rb +12 -9
- data/lib/valvat/checksum/gr.rb +2 -2
- data/lib/valvat/checksum/ie.rb +2 -2
- data/lib/valvat/checksum/it.rb +1 -4
- data/lib/valvat/checksum/nl.rb +2 -2
- data/lib/valvat/checksum/pt.rb +1 -3
- data/lib/valvat/checksum/se.rb +1 -3
- data/lib/valvat/checksum/si.rb +1 -3
- data/lib/valvat/locales/de.yml +1 -1
- data/lib/valvat/locales/pt.yml +29 -29
- data/lib/valvat/lookup.rb +59 -32
- data/lib/valvat/lookup/request.rb +1 -1
- data/lib/valvat/lookup/request_with_id.rb +1 -1
- data/lib/valvat/syntax.rb +1 -1
- data/lib/valvat/version.rb +1 -1
- data/spec/active_model/validations/valvat_validator_spec.rb +242 -0
- data/spec/spec_helper.rb +16 -10
- data/spec/valvat/lookup_spec.rb +38 -27
- data/spec/valvat/syntax_spec.rb +3 -0
- data/valvat.gemspec +1 -1
- metadata +11 -7
- data/lib/valvat/active_model.rb +0 -45
- data/spec/valvat/active_model_spec.rb +0 -240
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c91978204cfd4d62e0e63532f7ba5050ffb961ff
|
4
|
+
data.tar.gz: 3a3c0cc26abeef11d53eeca8b217f9315f15b99d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3da453e8fd22a40fa17395ce4726d4688be3a5c156ecb3d7b267c7b88c416f5764ad613774afdf41021ad7c047580f1bf3c672da8203e70b4fb9ac2ef0b5a8ef
|
7
|
+
data.tar.gz: 24b21743ebf0a7f824f36c3a4a87184ad1fd981b5c8aca00627939ac87639c763116707106a47313af691aff4b226b8ae33c3ed9f0f240b425ee1012a3895b07
|
data/.travis.yml
ADDED
data/CHANGES.md
CHANGED
@@ -1,6 +1,16 @@
|
|
1
1
|
### dev
|
2
2
|
|
3
|
-
[full changelog](http://github.com/yolk/valvat/compare/v0.
|
3
|
+
[full changelog](http://github.com/yolk/valvat/compare/v0.6.0...master)
|
4
|
+
|
5
|
+
### 0.6.0 / 2013-08-01
|
6
|
+
|
7
|
+
[full changelog](http://github.com/yolk/valvat/compare/v0.5.0...v0.6.0)
|
8
|
+
|
9
|
+
* Works now with current version of savon gem (2.3.0) (by [liggitt](https://github.com/liggitt))
|
10
|
+
* Corrected regex for IE VAT numbers (by [brianphillips](https://github.com/brianphillips))
|
11
|
+
* Improved PT translation
|
12
|
+
* Some code refactorings
|
13
|
+
* Spec improvments
|
4
14
|
|
5
15
|
### 0.5.0 / 2013-07-18
|
6
16
|
|
data/README.md
CHANGED
@@ -1,4 +1,7 @@
|
|
1
|
-
|
1
|
+
valvat
|
2
|
+
===========
|
3
|
+
|
4
|
+
[](http://badge.fury.io/rb/valvat) [](https://travis-ci.org/yolk/valvat) [](https://codeclimate.com/github/yolk/valvat)
|
2
5
|
|
3
6
|
Validates european vat numbers. Standalone or as a ActiveModel validator.
|
4
7
|
|
@@ -11,7 +14,7 @@ Validates european vat numbers. Standalone or as a ActiveModel validator.
|
|
11
14
|
* I18n locales for country specific error messages in English, German, Swedish, Italian, Portuguese, Polish, Bulgarian, Romanian and Latvian.
|
12
15
|
* *Experimental* checksum verification
|
13
16
|
|
14
|
-
valvat is tested and works with ruby 1.
|
17
|
+
valvat is tested and works with ruby 1.9.3/2.0 and ActiveModel 3.2/4.0
|
15
18
|
|
16
19
|
## Installation
|
17
20
|
|
@@ -47,8 +50,8 @@ Or to lookup a vat number string directly via VIES web service:
|
|
47
50
|
|
48
51
|
valvat allows to check vat numbers from AT, BE, BG, DE, DK, ES, FI, GR, IE, IT, LU, NL, PL, PT, SE and SI against a checksum calculation. All other countries will fall back to a simple syntax check:
|
49
52
|
|
50
|
-
|
51
|
-
|
53
|
+
Valvat.new("DE345789003").valid_checksum?
|
54
|
+
=> true or false
|
52
55
|
|
53
56
|
These results are more valuabel than a simple syntax check, but keep in mind: they can not replace a lookup via VIES.
|
54
57
|
|
@@ -56,8 +59,8 @@ These results are more valuabel than a simple syntax check, but keep in mind: th
|
|
56
59
|
|
57
60
|
To bypass initializing a Valvat instance:
|
58
61
|
|
59
|
-
|
60
|
-
|
62
|
+
Valvat::Checksum.validate("DE345789003")
|
63
|
+
=> true or false
|
61
64
|
|
62
65
|
## Details & request identifier
|
63
66
|
|
@@ -88,7 +91,7 @@ To receive a requestIdentifier you need to pass your own VAT number in the optio
|
|
88
91
|
|
89
92
|
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
|
90
93
|
|
91
|
-
require '
|
94
|
+
require 'active_model/validations/valvat_validator'
|
92
95
|
|
93
96
|
after ActiveModel has been loaded.
|
94
97
|
|
@@ -181,6 +184,9 @@ This basically just removes trailing spaces and ensures all chars are uppercase.
|
|
181
184
|
|
182
185
|
## Contributions by
|
183
186
|
|
187
|
+
* [brianphillips](https://github.com/brianphillips)
|
188
|
+
* [wasi](https://github.com/wasi)
|
189
|
+
* [liggitt](https://github.com/liggitt)
|
184
190
|
* [nevesenin](https://github.com/nevesenin)
|
185
191
|
* [shaundaley39](https://github.com/shaundaley39)
|
186
192
|
* [lcx](https://github.com/lcx)
|
data/gemfiles/standalone
ADDED
@@ -0,0 +1,54 @@
|
|
1
|
+
require 'active_model'
|
2
|
+
require 'valvat/syntax'
|
3
|
+
require 'valvat/lookup'
|
4
|
+
|
5
|
+
module ActiveModel
|
6
|
+
module Validations
|
7
|
+
class ValvatValidator < EachValidator
|
8
|
+
def validate_each(record, attribute, value)
|
9
|
+
vat = Valvat(value)
|
10
|
+
iso_country_code = vat.iso_country_code
|
11
|
+
|
12
|
+
if country_does_not_match?(record, iso_country_code)
|
13
|
+
iso_country_code = iso_country_code_of(record)
|
14
|
+
elsif vat.valid? && valid_checksum?(vat) && vat_exists?(vat)
|
15
|
+
return
|
16
|
+
end
|
17
|
+
|
18
|
+
iso_country_code = "eu" if iso_country_code.blank?
|
19
|
+
record.errors.add(attribute, :invalid_vat,
|
20
|
+
:message => options[:message],
|
21
|
+
:country_adjective => I18n.t(
|
22
|
+
:"valvat.country_adjectives.#{iso_country_code.downcase}",
|
23
|
+
:default => [:"valvat.country_adjectives.eu", "european"]
|
24
|
+
)
|
25
|
+
)
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
29
|
+
|
30
|
+
def country_does_not_match?(record, iso_country_code)
|
31
|
+
return false unless options[:match_country]
|
32
|
+
iso_country_code_of(record) != iso_country_code
|
33
|
+
end
|
34
|
+
|
35
|
+
def iso_country_code_of(record)
|
36
|
+
(record.send(options[:match_country]) || "").upcase
|
37
|
+
end
|
38
|
+
|
39
|
+
def valid_checksum?(vat)
|
40
|
+
return true unless options[:checksum]
|
41
|
+
vat.valid_checksum?
|
42
|
+
end
|
43
|
+
|
44
|
+
def vat_exists?(vat)
|
45
|
+
return true unless options[:lookup]
|
46
|
+
is_valid = vat.exists?
|
47
|
+
return is_valid unless is_valid.nil?
|
48
|
+
options[:lookup] != :fail_if_down
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
I18n.load_path += Dir["#{File.dirname(__FILE__)}/../../valvat/locales/*.yml"]
|
data/lib/valvat.rb
CHANGED
data/lib/valvat/checksum.rb
CHANGED
@@ -51,10 +51,31 @@ class Valvat
|
|
51
51
|
def str_wo_country
|
52
52
|
vat.to_s_wo_country
|
53
53
|
end
|
54
|
+
|
55
|
+
def sum_figures_by
|
56
|
+
figures.reverse.each_with_index.map do |fig, i|
|
57
|
+
yield(fig, i)
|
58
|
+
end.inject(:+)
|
59
|
+
end
|
60
|
+
|
61
|
+
def sum_of_squares(num)
|
62
|
+
num.to_s.split("").map(&:to_i).inject(:+)
|
63
|
+
end
|
64
|
+
|
65
|
+
def sum_of_figures_for_at_es_it_se(reverse_ints=false)
|
66
|
+
ints = reverse_ints ? [2, 1] : [1, 2]
|
67
|
+
sum_figures_by do |fig, i|
|
68
|
+
sum_of_squares(fig*(i.modulo(2) == 0 ? ints[0] : ints[1]))
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
def sum_of_figues_for_pt_si
|
73
|
+
11 - sum_figures_by do |fig, i|
|
74
|
+
fig*(i+2)
|
75
|
+
end.modulo(11)
|
76
|
+
end
|
54
77
|
end
|
55
78
|
end
|
56
79
|
end
|
57
80
|
|
58
|
-
Dir
|
59
|
-
require file
|
60
|
-
end
|
81
|
+
Dir.glob(File.dirname(__FILE__) + "/checksum/*.rb", &method(:require))
|
data/lib/valvat/checksum/at.rb
CHANGED
@@ -4,9 +4,7 @@ class Valvat
|
|
4
4
|
module Checksum
|
5
5
|
class AT < Base
|
6
6
|
def check_digit
|
7
|
-
chk = 96 -
|
8
|
-
(fig*(i.modulo(2) == 0 ? 1 : 2)).to_s.split("").inject(0) { |sum, n| sum + n.to_i }
|
9
|
-
end.inject(:+)
|
7
|
+
chk = 96 - sum_of_figures_for_at_es_it_se
|
10
8
|
chk.to_s[-1].to_i
|
11
9
|
end
|
12
10
|
|
data/lib/valvat/checksum/bg.rb
CHANGED
@@ -4,31 +4,31 @@ class Valvat
|
|
4
4
|
def check_digit
|
5
5
|
natural_person? ? check_digit_natural_person : check_digit_legal_person
|
6
6
|
end
|
7
|
-
|
7
|
+
|
8
8
|
def check_digit_natural_person
|
9
9
|
local_person_chk = check_digit_local_natural_person
|
10
10
|
|
11
11
|
return local_person_chk if given_check_digit == local_person_chk
|
12
12
|
check_digit_foreign_natural_person
|
13
13
|
end
|
14
|
-
|
14
|
+
|
15
15
|
def check_digit_local_natural_person
|
16
16
|
weight = [2, 4, 8, 5, 10, 9, 7, 3, 6]
|
17
17
|
chk = figures.map do |fig|
|
18
18
|
fig * weight.shift
|
19
19
|
end.inject(:+).modulo(11)
|
20
|
-
|
20
|
+
|
21
21
|
return chk if chk < 10
|
22
22
|
return 0
|
23
23
|
end
|
24
|
-
|
24
|
+
|
25
25
|
def check_digit_foreign_natural_person
|
26
26
|
weight = [21, 19, 17, 13, 11, 9, 7, 3, 1]
|
27
27
|
|
28
28
|
chk = figures.map do |fig|
|
29
29
|
fig * weight.shift
|
30
30
|
end.inject(:+).modulo(10)
|
31
|
-
|
31
|
+
|
32
32
|
chk
|
33
33
|
end
|
34
34
|
|
@@ -37,22 +37,22 @@ class Valvat
|
|
37
37
|
figures.each_with_index do |fig, index|
|
38
38
|
prod += (index + 1) * fig.to_i
|
39
39
|
end
|
40
|
-
|
40
|
+
|
41
41
|
chk = prod % 11
|
42
|
-
|
42
|
+
|
43
43
|
if chk == 10
|
44
44
|
prod = 0
|
45
45
|
figures.each_with_index do |fig, index|
|
46
46
|
prod += (index + 3) * fig.to_i
|
47
47
|
end
|
48
|
-
|
48
|
+
|
49
49
|
chk = prod % 11
|
50
50
|
chk = 0 if chk == 10
|
51
51
|
end
|
52
|
-
|
52
|
+
|
53
53
|
chk
|
54
54
|
end
|
55
|
-
|
55
|
+
|
56
56
|
def natural_person?
|
57
57
|
vat.to_s_wo_country.length == 10
|
58
58
|
end
|
data/lib/valvat/checksum/es.rb
CHANGED
@@ -4,7 +4,9 @@ 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)
|
7
|
+
NATURAL_PERSON_EXP = /\A([\d]{8}[ABCDEFGHJKLMNPQRSTVWXYZ]|[KLMX][\d]{7}[ABCDEFGHJKLMNPQRSTVWXYZ])\Z/
|
7
8
|
LEGAL_FOREIGN_PERSON_CHARS = [false] + %w(A B C D E F G H I J)
|
9
|
+
LEGAL_FOREIGN_PERSON_EXP = /\A[NPQRSW][\d]{7}[ABCDEFGHIJ]\Z/
|
8
10
|
|
9
11
|
def check_digit
|
10
12
|
natural_person? ? check_digit_natural_person : check_digit_legal_person
|
@@ -15,16 +17,14 @@ class Valvat
|
|
15
17
|
end
|
16
18
|
|
17
19
|
def check_digit_legal_person
|
18
|
-
chk = 10 -
|
19
|
-
|
20
|
-
|
21
|
-
legal_foreign_person? ?
|
22
|
-
LEGAL_FOREIGN_PERSON_CHARS[chk] :
|
20
|
+
chk = 10 - sum_of_figures_for_at_es_it_se(true).modulo(10)
|
21
|
+
legal_foreign_person? ?
|
22
|
+
LEGAL_FOREIGN_PERSON_CHARS[chk] :
|
23
23
|
(chk == 10 ? 0 : chk)
|
24
24
|
end
|
25
25
|
|
26
26
|
def given_check_digit
|
27
|
-
|
27
|
+
person? ? str_wo_country[-1] : super
|
28
28
|
end
|
29
29
|
|
30
30
|
def str_wo_country
|
@@ -32,13 +32,16 @@ class Valvat
|
|
32
32
|
str[0] =~ /\d/ ? str : str[1..-1]
|
33
33
|
end
|
34
34
|
|
35
|
+
def person?
|
36
|
+
natural_person? || legal_foreign_person?
|
37
|
+
end
|
38
|
+
|
35
39
|
def natural_person?
|
36
|
-
!!(vat.to_s_wo_country =~
|
37
|
-
!!(vat.to_s_wo_country =~ /\A[KLMX][\d]{7}[ABCDEFGHJKLMNPQRSTVWXYZ]\Z/)
|
40
|
+
!!(vat.to_s_wo_country =~ NATURAL_PERSON_EXP)
|
38
41
|
end
|
39
42
|
|
40
43
|
def legal_foreign_person?
|
41
|
-
!!(vat.to_s_wo_country =~
|
44
|
+
!!(vat.to_s_wo_country =~ LEGAL_FOREIGN_PERSON_EXP)
|
42
45
|
end
|
43
46
|
end
|
44
47
|
end
|
data/lib/valvat/checksum/gr.rb
CHANGED
data/lib/valvat/checksum/ie.rb
CHANGED
@@ -4,9 +4,9 @@ class Valvat
|
|
4
4
|
module Checksum
|
5
5
|
class IE < Base
|
6
6
|
def check_digit
|
7
|
-
|
7
|
+
sum_figures_by do |fig, i|
|
8
8
|
fig*(i+2)
|
9
|
-
end.
|
9
|
+
end.modulo(23)
|
10
10
|
end
|
11
11
|
|
12
12
|
CHARS = "WABCDEFGHIJKLMNOPQRSTUV".split("")
|
data/lib/valvat/checksum/it.rb
CHANGED
@@ -4,7 +4,6 @@ class Valvat
|
|
4
4
|
module Checksum
|
5
5
|
class IT < Base
|
6
6
|
def validate
|
7
|
-
# IT02762750210
|
8
7
|
y = figures_str[7..9].to_i
|
9
8
|
y >= 1 && (y <= 100 || [120, 121].include?(y)) &&
|
10
9
|
figures_str[0..6] != "0000000" &&
|
@@ -12,9 +11,7 @@ class Valvat
|
|
12
11
|
end
|
13
12
|
|
14
13
|
def check_digit
|
15
|
-
chk = 10 -
|
16
|
-
(fig*(i.modulo(2) == 0 ? 2 : 1)).to_s.split("").inject(0) { |sum, n| sum + n.to_i }
|
17
|
-
end.inject(:+).modulo(10)
|
14
|
+
chk = 10 - sum_of_figures_for_at_es_it_se(true).modulo(10)
|
18
15
|
chk == 10 ? 0 : chk
|
19
16
|
end
|
20
17
|
end
|
data/lib/valvat/checksum/nl.rb
CHANGED
data/lib/valvat/checksum/pt.rb
CHANGED
data/lib/valvat/checksum/se.rb
CHANGED
@@ -13,9 +13,7 @@ class Valvat
|
|
13
13
|
private
|
14
14
|
|
15
15
|
def check_digit
|
16
|
-
|
17
|
-
(fig*(i.modulo(2) == 0 ? 1 : 2)).to_s.split("").inject(0) { |sum, n| sum + n.to_i }
|
18
|
-
end.inject(:+).modulo(10)
|
16
|
+
sum_of_figures_for_at_es_it_se.modulo(10)
|
19
17
|
end
|
20
18
|
|
21
19
|
def given_check_digit
|
data/lib/valvat/checksum/si.rb
CHANGED