valvat 1.0.1 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (104) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data.tar.gz.sig +0 -0
  4. data/.github/workflows/ruby.yml +35 -0
  5. data/.gitignore +1 -0
  6. data/.rubocop.yml +15 -0
  7. data/CHANGES.md +9 -1
  8. data/Gemfile +2 -0
  9. data/Guardfile +6 -4
  10. data/README.md +5 -3
  11. data/Rakefile +3 -1
  12. data/gemfiles/activemodel-5 +1 -1
  13. data/gemfiles/activemodel-6 +1 -1
  14. data/lib/active_model/validations/valvat_validator.rb +65 -32
  15. data/lib/valvat.rb +4 -2
  16. data/lib/valvat/checksum.rb +14 -13
  17. data/lib/valvat/checksum/at.rb +3 -1
  18. data/lib/valvat/checksum/be.rb +3 -1
  19. data/lib/valvat/checksum/bg.rb +17 -17
  20. data/lib/valvat/checksum/cy.rb +2 -0
  21. data/lib/valvat/checksum/de.rb +5 -3
  22. data/lib/valvat/checksum/dk.rb +3 -1
  23. data/lib/valvat/checksum/ee.rb +2 -0
  24. data/lib/valvat/checksum/es.rb +14 -16
  25. data/lib/valvat/checksum/fi.rb +3 -1
  26. data/lib/valvat/checksum/fr.rb +4 -2
  27. data/lib/valvat/checksum/gb.rb +46 -31
  28. data/lib/valvat/checksum/gr.rb +4 -2
  29. data/lib/valvat/checksum/hr.rb +2 -0
  30. data/lib/valvat/checksum/hu.rb +2 -0
  31. data/lib/valvat/checksum/ie.rb +5 -6
  32. data/lib/valvat/checksum/it.rb +6 -4
  33. data/lib/valvat/checksum/lt.rb +2 -0
  34. data/lib/valvat/checksum/lu.rb +3 -1
  35. data/lib/valvat/checksum/mt.rb +2 -0
  36. data/lib/valvat/checksum/nl.rb +5 -3
  37. data/lib/valvat/checksum/pl.rb +3 -1
  38. data/lib/valvat/checksum/pt.rb +3 -1
  39. data/lib/valvat/checksum/ro.rb +2 -0
  40. data/lib/valvat/checksum/se.rb +5 -3
  41. data/lib/valvat/checksum/si.rb +4 -2
  42. data/lib/valvat/error.rb +4 -1
  43. data/lib/valvat/local.rb +6 -4
  44. data/lib/valvat/locales/de.yml +2 -1
  45. data/lib/valvat/locales/en.yml +2 -1
  46. data/lib/valvat/locales/es.yml +1 -0
  47. data/lib/valvat/locales/fr.yml +1 -0
  48. data/lib/valvat/locales/hu.yml +1 -0
  49. data/lib/valvat/locales/nl.yml +1 -0
  50. data/lib/valvat/locales/pl.yml +1 -0
  51. data/lib/valvat/lookup.rb +5 -4
  52. data/lib/valvat/lookup/fault.rb +17 -16
  53. data/lib/valvat/lookup/request.rb +21 -16
  54. data/lib/valvat/lookup/response.rb +11 -10
  55. data/lib/valvat/syntax.rb +31 -30
  56. data/lib/valvat/utils.rb +12 -9
  57. data/lib/valvat/version.rb +3 -1
  58. data/spec/active_model/validations/valvat_validator_spec.rb +99 -93
  59. data/spec/spec_helper.rb +8 -8
  60. data/spec/valvat/checksum/at_spec.rb +6 -4
  61. data/spec/valvat/checksum/be_spec.rb +6 -4
  62. data/spec/valvat/checksum/bg_spec.rb +7 -4
  63. data/spec/valvat/checksum/cy_spec.rb +3 -1
  64. data/spec/valvat/checksum/de_spec.rb +6 -4
  65. data/spec/valvat/checksum/dk_spec.rb +6 -4
  66. data/spec/valvat/checksum/ee_spec.rb +3 -1
  67. data/spec/valvat/checksum/es_spec.rb +7 -4
  68. data/spec/valvat/checksum/fi_spec.rb +6 -4
  69. data/spec/valvat/checksum/fr_spec.rb +6 -4
  70. data/spec/valvat/checksum/gb_spec.rb +4 -2
  71. data/spec/valvat/checksum/gr_spec.rb +6 -4
  72. data/spec/valvat/checksum/hr_spec.rb +3 -1
  73. data/spec/valvat/checksum/hu_spec.rb +3 -1
  74. data/spec/valvat/checksum/ie_spec.rb +8 -6
  75. data/spec/valvat/checksum/it_spec.rb +10 -8
  76. data/spec/valvat/checksum/lt_spec.rb +3 -1
  77. data/spec/valvat/checksum/lu_spec.rb +6 -4
  78. data/spec/valvat/checksum/mt_spec.rb +3 -1
  79. data/spec/valvat/checksum/nl_spec.rb +9 -7
  80. data/spec/valvat/checksum/pl_spec.rb +8 -6
  81. data/spec/valvat/checksum/pt_spec.rb +10 -11
  82. data/spec/valvat/checksum/ro_spec.rb +3 -1
  83. data/spec/valvat/checksum/se_spec.rb +8 -6
  84. data/spec/valvat/checksum/si_spec.rb +10 -8
  85. data/spec/valvat/checksum_spec.rb +11 -9
  86. data/spec/valvat/lookup/fault_spec.rb +34 -0
  87. data/spec/valvat/lookup/request_spec.rb +19 -0
  88. data/spec/valvat/lookup/response_spec.rb +29 -0
  89. data/spec/valvat/lookup_spec.rb +138 -153
  90. data/spec/valvat/syntax_spec.rb +59 -280
  91. data/spec/valvat/utils_spec.rb +62 -47
  92. data/spec/valvat_spec.rb +140 -152
  93. data/valvat.gemspec +17 -17
  94. metadata +24 -27
  95. metadata.gz.sig +0 -0
  96. data/.travis.yml +0 -47
  97. data/gemfiles/activemodel-3-2 +0 -7
  98. data/gemfiles/activemodel-4 +0 -7
  99. data/gemfiles/before-ruby21/activemodel-3-2 +0 -8
  100. data/gemfiles/before-ruby21/activemodel-4 +0 -8
  101. data/gemfiles/before-ruby21/standalone +0 -7
  102. data/spec/valvat/lockup/fault_spec.rb +0 -32
  103. data/spec/valvat/lockup/request_spec.rb +0 -15
  104. data/spec/valvat/lockup/response_spec.rb +0 -27
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class Valvat
2
4
  module Checksum
3
5
  class CY < Base
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class Valvat
2
4
  module Checksum
3
5
  class DE < Base
@@ -8,12 +10,12 @@ class Valvat
8
10
  prod = M
9
11
  figures.each do |fig|
10
12
  sum = (prod + fig).modulo(M)
11
- sum = M if sum == 0
12
- prod = (2*sum).modulo(N)
13
+ sum = M if sum.zero?
14
+ prod = (2 * sum).modulo(N)
13
15
  end
14
16
  chk = N - prod
15
17
  chk == 10 ? 0 : chk
16
18
  end
17
19
  end
18
20
  end
19
- end
21
+ end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class Valvat
2
4
  module Checksum
3
5
  class DK < Base
@@ -15,4 +17,4 @@ class Valvat
15
17
  end
16
18
  end
17
19
  end
18
- end
20
+ end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class Valvat
2
4
  module Checksum
3
5
  class EE < Base
@@ -1,33 +1,31 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class Valvat
2
4
  module Checksum
3
5
  class ES < Base
4
- 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)
5
- NATURAL_PERSON_EXP = /\A([\d]{8}[ABCDEFGHJKLMNPQRSTVWXYZ]|[KLMXYZ][\d]{7}[ABCDEFGHJKLMNPQRSTVWXYZ])\Z/
6
- LEGAL_PERSON_CHARS = [false] + %w(A B C D E F G H I J)
7
- LEGAL_PERSON_EXP = /\A[NPQRSW][\d]{7}[ABCDEFGHIJ]\Z/
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(\d{8}[ABCDEFGHJKLMNPQRSTVWXYZ]|[KLMXYZ]\d{7}[ABCDEFGHJKLMNPQRSTVWXYZ])\Z/.freeze
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
+ NIE_DIGIT_BY_LETTER = %w[X Y Z].freeze
8
11
 
9
12
  def check_digit
10
13
  natural_person? ? check_digit_natural_person : check_digit_legal_person
11
14
  end
12
15
 
13
16
  def check_digit_natural_person
14
- nie_digit = nil
15
17
  letter = vat.to_s_wo_country[0]
16
- if letter == 'X'
17
- nie_digit = 0
18
- elsif letter == 'Y'
19
- nie_digit = 1
20
- elsif letter == 'Z'
21
- nie_digit = 2
22
- end
18
+ nie_digit = NIE_DIGIT_BY_LETTER.index(letter)
23
19
  NATURAL_PERSON_CHARS["#{nie_digit}#{figures_str}".to_i.modulo(23)]
24
20
  end
25
21
 
26
22
  def check_digit_legal_person
27
- chk = 10 - sum_of_figures_for_at_es_it_se(true).modulo(10)
28
- legal_foreign_person? ?
29
- LEGAL_PERSON_CHARS[chk] :
23
+ chk = 10 - sum_of_figures_for_at_es_it_se(reverse_ints: true).modulo(10)
24
+ if legal_foreign_person?
25
+ LEGAL_PERSON_CHARS[chk]
26
+ else
30
27
  (chk == 10 ? 0 : chk)
28
+ end
31
29
  end
32
30
 
33
31
  def given_check_digit
@@ -52,4 +50,4 @@ class Valvat
52
50
  end
53
51
  end
54
52
  end
55
- end
53
+ end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class Valvat
2
4
  module Checksum
3
5
  class FI < Base
@@ -10,4 +12,4 @@ class Valvat
10
12
  end
11
13
  end
12
14
  end
13
- end
15
+ end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class Valvat
2
4
  module Checksum
3
5
  class FR < Base
@@ -5,10 +7,10 @@ class Valvat
5
7
  siren = str_wo_country[2..-1].to_i
6
8
  (12 + (3 * siren) % 97) % 97
7
9
  end
8
-
10
+
9
11
  def given_check_digit
10
12
  str_wo_country[0..1].to_i
11
13
  end
12
14
  end
13
15
  end
14
- end
16
+ end
@@ -1,51 +1,66 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class Valvat
2
4
  module Checksum
3
5
  class GB < Base
4
- OLD_FORMAT_FORBIDDEN_RANGES = [(100_000..999_999), (9_490_001..9_700_000), (9_990_001..9_999_999)]
5
- NEW_FORMAT_FORBIDDEN_RANGES = [(1..100_000), (100_001..1_000_000)]
6
- GOV_NUMBER = /\A(GD[0-4]{1}\d{2})\Z/
7
- HEALTH_NUMBER = /\A(HA[5-9]{1}\d{2})\Z/
8
-
9
- def validate
10
- vat_number = vat.to_s_wo_country
6
+ OLD_FORMAT_FORBIDDEN_RANGES = [(100_000..999_999), (9_490_001..9_700_000), (9_990_001..9_999_999)].freeze
7
+ NEW_FORMAT_FORBIDDEN_RANGES = [(1..100_000), (100_001..1_000_000)].freeze
8
+ GOV_NUMBER = /\A(GD[0-4]{1}\d{2})\Z/.freeze
9
+ HEALTH_NUMBER = /\A(HA[5-9]{1}\d{2})\Z/.freeze
11
10
 
11
+ def validate # rubocop:disable Metrics/CyclomaticComplexity
12
12
  # government departments and health authorities, so no checksum
13
- return true if gov_or_health?(vat_number)
14
- return false if all_zero?(vat_number)
13
+ return true if gov_or_health?
14
+ return false if all_zero?
15
15
 
16
- checksum = vat_number[7..8].to_i
17
- vat_base = vat_number[0..6]
18
- vat_base_int = vat_base.to_i
19
- vat_base_sum = generate_vat_base_sum(vat_base)
16
+ return false if old_format_remainder.zero? && fobidden_in_old_format?
17
+ return false if new_format_remainder.zero? && fobidden_in_new_format?
20
18
 
21
- old_format_remainder = (vat_base_sum + checksum).modulo(97)
22
- new_format_remainder = (vat_base_sum + 55 + checksum).modulo(97)
19
+ old_format_remainder.zero? || new_format_remainder.zero?
20
+ end
23
21
 
24
- return false if old_format_remainder == 0 &&
25
- OLD_FORMAT_FORBIDDEN_RANGES.any? { |range| range.include? vat_base_int }
22
+ private
26
23
 
27
- return false if new_format_remainder == 0 &&
28
- NEW_FORMAT_FORBIDDEN_RANGES.any? { |range| range.include? vat_base_int }
24
+ def checksum
25
+ @checksum ||= str_wo_country[7..8].to_i
26
+ end
29
27
 
30
- old_format_remainder == 0 || new_format_remainder == 0
28
+ def vat_base
29
+ @vat_base ||= str_wo_country[0..6]
31
30
  end
32
31
 
33
- private
32
+ def gov_or_health?
33
+ str_wo_country =~ GOV_NUMBER || str_wo_country =~ HEALTH_NUMBER
34
+ end
34
35
 
35
- def gov_or_health?(vat_number)
36
- vat_number =~ GOV_NUMBER || vat_number =~ HEALTH_NUMBER
36
+ def all_zero?
37
+ str_wo_country =~ /\A0{9}\Z/ || str_wo_country =~ /\A0{12}\Z/
37
38
  end
38
39
 
39
- def all_zero?(vat_number)
40
- vat_number =~ /\A0{9}\Z/ || vat_number =~ /\A0{12}\Z/
40
+ def vat_base_sum
41
+ @vat_base_sum ||= vat_base.split('')
42
+ .map(&:to_i)
43
+ .zip([8, 7, 6, 5, 4, 3, 2])
44
+ .map { |vat_number_digit, multiplier| vat_number_digit * multiplier }
45
+ .inject(:+)
41
46
  end
42
47
 
43
- def generate_vat_base_sum(vat_base)
44
- vat_base.split('').
45
- map(&:to_i).
46
- zip([8, 7, 6, 5, 4, 3, 2]).
47
- map { |vat_number_digit, multiplier| vat_number_digit * multiplier }.
48
- inject(:+)
48
+ def old_format_remainder
49
+ @old_format_remainder ||= (vat_base_sum + checksum).modulo(97)
50
+ end
51
+
52
+ def new_format_remainder
53
+ @new_format_remainder ||= (vat_base_sum + 55 + checksum).modulo(97)
54
+ end
55
+
56
+ def fobidden_in_new_format?
57
+ vat_base_int = vat_base.to_i
58
+ NEW_FORMAT_FORBIDDEN_RANGES.any? { |range| range.include?(vat_base_int) }
59
+ end
60
+
61
+ def fobidden_in_old_format?
62
+ vat_base_int = vat_base.to_i
63
+ OLD_FORMAT_FORBIDDEN_RANGES.any? { |range| range.include?(vat_base_int) }
49
64
  end
50
65
  end
51
66
  end
@@ -1,12 +1,14 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class Valvat
2
4
  module Checksum
3
5
  class GR < Base
4
6
  def check_digit
5
7
  chk = sum_figures_by do |fig, i|
6
- fig*(2**(i+1))
8
+ fig * (2**(i + 1))
7
9
  end.modulo(11)
8
10
  chk > 9 ? 0 : chk
9
11
  end
10
12
  end
11
13
  end
12
- end
14
+ end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class Valvat
2
4
  module Checksum
3
5
  class HR < Base
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class Valvat
2
4
  module Checksum
3
5
  class HU < Base
@@ -1,17 +1,17 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class Valvat
2
4
  module Checksum
3
5
  class IE < Base
4
6
  def check_digit
5
7
  total = sum_figures_by do |fig, i|
6
- fig*(i+2)
7
- end
8
- if str_wo_country.size == 9
9
- total += ((CHARS.index(str_wo_country[8]) || 0) * 9)
8
+ fig * (i + 2)
10
9
  end
10
+ total += ((CHARS.index(str_wo_country[8]) || 0) * 9) if str_wo_country.size == 9
11
11
  total.modulo(23)
12
12
  end
13
13
 
14
- CHARS = "WABCDEFGHIJKLMNOPQRSTUV".split("")
14
+ CHARS = 'WABCDEFGHIJKLMNOPQRSTUV'.split('')
15
15
 
16
16
  def given_check_digit
17
17
  if str_wo_country.size == 9
@@ -38,7 +38,6 @@ class Valvat
38
38
  super
39
39
  end
40
40
  end
41
-
42
41
  end
43
42
  end
44
43
  end
@@ -1,17 +1,19 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class Valvat
2
4
  module Checksum
3
5
  class IT < Base
4
6
  def validate
5
7
  y = figures_str[7..9].to_i
6
8
  y >= 1 && (y <= 100 || [120, 121].include?(y)) &&
7
- figures_str[0..6] != "0000000" &&
8
- super
9
+ figures_str[0..6] != '0000000' &&
10
+ super
9
11
  end
10
12
 
11
13
  def check_digit
12
- chk = 10 - sum_of_figures_for_at_es_it_se(true).modulo(10)
14
+ chk = 10 - sum_of_figures_for_at_es_it_se(reverse_ints: true).modulo(10)
13
15
  chk == 10 ? 0 : chk
14
16
  end
15
17
  end
16
18
  end
17
- end
19
+ end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class Valvat
2
4
  module Checksum
3
5
  class LT < Base
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class Valvat
2
4
  module Checksum
3
5
  class LU < Base
@@ -8,4 +10,4 @@ class Valvat
8
10
  end
9
11
  end
10
12
  end
11
- end
13
+ end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class Valvat
2
4
  module Checksum
3
5
  class MT < Base
@@ -1,14 +1,16 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class Valvat
2
4
  module Checksum
3
5
  class NL < Base
4
6
  def validate
5
7
  vat.to_s.gsub(/[A-Z]/) { |let| (let.ord - 55).to_s }.to_i % 97 == 1 ||
6
- super
8
+ super
7
9
  end
8
10
 
9
11
  def check_digit
10
12
  sum_figures_by do |fig, i|
11
- fig*(i+2)
13
+ fig * (i + 2)
12
14
  end.modulo(11)
13
15
  end
14
16
 
@@ -17,4 +19,4 @@ class Valvat
17
19
  end
18
20
  end
19
21
  end
20
- end
22
+ end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class Valvat
2
4
  module Checksum
3
5
  class PL < Base
@@ -9,4 +11,4 @@ class Valvat
9
11
  end
10
12
  end
11
13
  end
12
- end
14
+ end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class Valvat
2
4
  module Checksum
3
5
  class PT < Base
@@ -7,4 +9,4 @@ class Valvat
7
9
  end
8
10
  end
9
11
  end
10
- end
12
+ end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class Valvat
2
4
  module Checksum
3
5
  class RO < Base
@@ -1,11 +1,13 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class Valvat
2
4
  module Checksum
3
5
  class SE < Base
4
6
  check_digit_length 0
5
7
 
6
8
  def validate
7
- vat.to_s_wo_country[-2..-1].to_i > 0 &&
8
- super
9
+ vat.to_s_wo_country[-2..-1].to_i.positive? &&
10
+ super
9
11
  end
10
12
 
11
13
  private
@@ -23,4 +25,4 @@ class Valvat
23
25
  end
24
26
  end
25
27
  end
26
- end
28
+ end
@@ -1,9 +1,11 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class Valvat
2
4
  module Checksum
3
5
  class SI < Base
4
6
  def validate
5
- figures_str.to_i > 999999 &&
6
- super
7
+ figures_str.to_i > 999_999 &&
8
+ super
7
9
  end
8
10
 
9
11
  def check_digit
@@ -1,9 +1,12 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class Valvat
2
4
  Error = Class.new(RuntimeError)
3
5
 
4
6
  class ViesError < Error
5
- def initialize(faultstring='UNKNOWN')
7
+ def initialize(faultstring = 'UNKNOWN')
6
8
  @faultstring = faultstring
9
+ super
7
10
  end
8
11
 
9
12
  def to_s