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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 2422dd0589a6a76903426d5b4e738e3b3c66c9c8
4
- data.tar.gz: 0f473b7a536cc5f8eb48a9071821e09f88f4e213
3
+ metadata.gz: c91978204cfd4d62e0e63532f7ba5050ffb961ff
4
+ data.tar.gz: 3a3c0cc26abeef11d53eeca8b217f9315f15b99d
5
5
  SHA512:
6
- metadata.gz: c871aec23db77c958785bb116b03348dd030946aeec3ed85b923b991fc98c084ebf146bda3a8a77459b411d556f14f39d8b0d612f758ec45122587999c2fc47e
7
- data.tar.gz: ddea5c3424e6f95c39858a6d1b1ef418b9b9afc8f1d65ce17cdf189ea8106c3446136230159c322307dd71e337e58000254df5d6c980a62cefba344c775fb6e2
6
+ metadata.gz: 3da453e8fd22a40fa17395ce4726d4688be3a5c156ecb3d7b267c7b88c416f5764ad613774afdf41021ad7c047580f1bf3c672da8203e70b4fb9ac2ef0b5a8ef
7
+ data.tar.gz: 24b21743ebf0a7f824f36c3a4a87184ad1fd981b5c8aca00627939ac87639c763116707106a47313af691aff4b226b8ae33c3ed9f0f240b425ee1012a3895b07
@@ -0,0 +1,8 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.0.0
4
+ - 1.9.3
5
+ gemfile:
6
+ - gemfiles/activemodel-4
7
+ - gemfiles/activemodel-3-2
8
+ - gemfiles/standalone
data/CHANGES.md CHANGED
@@ -1,6 +1,16 @@
1
1
  ### dev
2
2
 
3
- [full changelog](http://github.com/yolk/valvat/compare/v0.5.0...master)
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
- # valvat
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.8.7/1.9.3/2.0 and ActiveModel 3.2/4.0
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
- Valvat.new("DE345789003").valid_checksum?
51
- => true or false
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
- Valvat::Checksum.validate("DE345789003")
60
- => true or false
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 'valvat/active_model'
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)
@@ -0,0 +1,8 @@
1
+ source "http://rubygems.org"
2
+
3
+ gem "savon", "2.3.0"
4
+ gem "activemodel", "3.2.13"
5
+
6
+ gem 'rspec', '>= 2.4.0'
7
+ gem 'fakeweb', '>= 1.3.0'
8
+ gem 'rake'
@@ -0,0 +1,8 @@
1
+ source "http://rubygems.org"
2
+
3
+ gem "savon", "2.3.0"
4
+ gem "activemodel", "4.0"
5
+
6
+ gem 'rspec', '>= 2.4.0'
7
+ gem 'fakeweb', '>= 1.3.0'
8
+ gem 'rake'
@@ -0,0 +1,7 @@
1
+ source "http://rubygems.org"
2
+
3
+ gem "savon", "2.3.0"
4
+
5
+ gem 'rspec', '>= 2.4.0'
6
+ gem 'fakeweb', '>= 1.3.0'
7
+ gem 'rake'
@@ -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"]
@@ -51,4 +51,4 @@ require 'valvat/lookup'
51
51
  require 'valvat/lookup/request'
52
52
  require 'valvat/lookup/request_with_id'
53
53
  require 'valvat/version'
54
- require 'valvat/active_model' if defined?(ActiveModel)
54
+ require 'active_model/validations/valvat_validator' if defined?(ActiveModel)
@@ -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[File.dirname(__FILE__) + "/checksum/*.rb"].each do |file|
59
- require file
60
- end
81
+ Dir.glob(File.dirname(__FILE__) + "/checksum/*.rb", &method(:require))
@@ -4,9 +4,7 @@ class Valvat
4
4
  module Checksum
5
5
  class AT < Base
6
6
  def check_digit
7
- chk = 96 - figures.reverse.each_with_index.map do |fig, i|
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
 
@@ -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
@@ -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 - figures.reverse.each_with_index.map do |fig, i|
19
- (fig*(i.modulo(2) == 0 ? 2 : 1)).to_s.split("").inject(0) { |sum, n| sum + n.to_i }
20
- end.inject(:+).modulo(10)
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
- natural_person? || legal_foreign_person? ? str_wo_country[-1] : super
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 =~ /\A[\d]{8}[ABCDEFGHJKLMNPQRSTVWXYZ]\Z/) ||
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 =~ /\A[NPQRSW][\d]{7}[ABCDEFGHIJ]\Z/)
44
+ !!(vat.to_s_wo_country =~ LEGAL_FOREIGN_PERSON_EXP)
42
45
  end
43
46
  end
44
47
  end
@@ -4,9 +4,9 @@ class Valvat
4
4
  module Checksum
5
5
  class GR < Base
6
6
  def check_digit
7
- chk = figures.reverse.each_with_index.map do |fig, i|
7
+ chk = sum_figures_by do |fig, i|
8
8
  fig*(2**(i+1))
9
- end.inject(:+).modulo(11)
9
+ end.modulo(11)
10
10
  chk > 9 ? 0 : chk
11
11
  end
12
12
  end
@@ -4,9 +4,9 @@ class Valvat
4
4
  module Checksum
5
5
  class IE < Base
6
6
  def check_digit
7
- figures.reverse.each_with_index.map do |fig, i|
7
+ sum_figures_by do |fig, i|
8
8
  fig*(i+2)
9
- end.inject(:+).modulo(23)
9
+ end.modulo(23)
10
10
  end
11
11
 
12
12
  CHARS = "WABCDEFGHIJKLMNOPQRSTUV".split("")
@@ -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 - figures.reverse.each_with_index.map do |fig, i|
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
@@ -4,9 +4,9 @@ class Valvat
4
4
  module Checksum
5
5
  class NL < Base
6
6
  def check_digit
7
- figures.reverse.each_with_index.map do |fig, i|
7
+ sum_figures_by do |fig, i|
8
8
  fig*(i+2)
9
- end.inject(:+).modulo(11)
9
+ end.modulo(11)
10
10
  end
11
11
 
12
12
  def str_wo_country
@@ -4,9 +4,7 @@ class Valvat
4
4
  module Checksum
5
5
  class PT < Base
6
6
  def check_digit
7
- chk = 11 - figures.reverse.each_with_index.map do |fig, i|
8
- fig*(i+2)
9
- end.inject(:+).modulo(11)
7
+ chk = sum_of_figues_for_pt_si
10
8
  chk > 9 ? 0 : chk
11
9
  end
12
10
  end
@@ -13,9 +13,7 @@ class Valvat
13
13
  private
14
14
 
15
15
  def check_digit
16
- figures.reverse.each_with_index.map do |fig, i|
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
@@ -9,9 +9,7 @@ class Valvat
9
9
  end
10
10
 
11
11
  def check_digit
12
- chk = 11 - figures.reverse.each_with_index.map do |fig, i|
13
- fig*(i+2)
14
- end.inject(:+).modulo(11)
12
+ chk = sum_of_figues_for_pt_si
15
13
  chk == 1 ? 0 : chk
16
14
  end
17
15
  end
@@ -1,7 +1,7 @@
1
1
  de:
2
2
  errors:
3
3
  messages:
4
- invalid_vat: ist kein gültige %{country_adjective} UStId-Nr.
4
+ invalid_vat: ist keine gültige %{country_adjective} UStId-Nr.
5
5
  valvat:
6
6
  country_adjectives:
7
7
  eu: europäische