valvat 0.5.0 → 0.6.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
+
[![Gem Version](https://badge.fury.io/rb/valvat.png)](http://badge.fury.io/rb/valvat) [![Build Status](https://travis-ci.org/yolk/valvat.png)](https://travis-ci.org/yolk/valvat) [![Code Climate](https://codeclimate.com/github/yolk/valvat.png)](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