tin_valid 0.1.1 → 1.1.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.
@@ -0,0 +1,83 @@
1
+ # frozen_string_literal: true
2
+
3
+ module TinValid
4
+ class RomaniaTin
5
+ include TinValid::Helpers
6
+
7
+ def initialize(tin:, birth_date: nil)
8
+ @tin = tin
9
+ @birth_date = birth_date
10
+ end
11
+
12
+ attr_reader :tin, :birth_date
13
+
14
+ def valid? = valid_v1? || valid_v2?
15
+
16
+ private
17
+
18
+ MATCHER_V1 = %r{
19
+ \A
20
+ (?<century_code>[1-9])
21
+ (?<year>[0-9]{2})
22
+ (?<month>[0-1][0-9])
23
+ (?<day>[0-3][0-9])
24
+ (?<district>[0-5][0-9])
25
+ [0-9]{4}
26
+ \z
27
+ }x
28
+ private_constant :MATCHER_V1
29
+
30
+ MATCHER_V2 = %r{
31
+ \A
32
+ 9
33
+ 000
34
+ [0-9]{8,9}
35
+ \z
36
+ }x
37
+ private_constant :MATCHER_V2
38
+
39
+ # rubocop:disable Metrics/CyclomaticComplexity
40
+ # rubocop:disable Metrics/MethodLength
41
+ def valid_v1?
42
+ match = MATCHER_V1.match(tin)
43
+ return false unless match
44
+ return false unless valid_district?(match[:district])
45
+
46
+ century = tin_century_from_code(match[:century_code]) || birth_century
47
+ if century
48
+ tin_date = date(
49
+ "#{century}#{match[:year]}",
50
+ match[:month],
51
+ match[:day],
52
+ )
53
+ return false if tin_date.nil?
54
+ return false if birth_date && tin_date != birth_date
55
+ end
56
+
57
+ true
58
+ end
59
+ # rubocop:enable Metrics/CyclomaticComplexity
60
+ # rubocop:enable Metrics/MethodLength
61
+
62
+ def valid_v2? = MATCHER_V2.match?(tin)
63
+
64
+ def valid_district?(district)
65
+ case district.to_i
66
+ when 1..47, 51..52 then true
67
+ else false
68
+ end
69
+ end
70
+
71
+ def birth_century
72
+ birth_date.year.to_s[..1] if birth_date
73
+ end
74
+
75
+ def tin_century_from_code(code)
76
+ case code.to_i
77
+ when 1..2 then 19
78
+ when 3..4 then 18
79
+ when 5..6 then 20
80
+ end
81
+ end
82
+ end
83
+ end
@@ -0,0 +1,67 @@
1
+ # frozen_string_literal: true
2
+
3
+ module TinValid
4
+ class SlovakiaTin
5
+ include TinValid::Helpers
6
+
7
+ def initialize(tin:, birth_date: nil)
8
+ @tin = tin
9
+ @birth_date = birth_date
10
+ end
11
+
12
+ attr_reader :tin, :birth_date
13
+
14
+ def valid?
15
+ return false if %w[0000000000 000000000 1234567890].include?(tin)
16
+
17
+ valid_v2? || valid_v1?
18
+ end
19
+
20
+ def normalized = tin.tr("/", "")
21
+
22
+ private
23
+
24
+ MATCHER_V1 = %r{
25
+ \A
26
+ (?<year>[0-9]{2})
27
+ (?<month>[0-6][0-9])
28
+ (?<day>[0-3][0-9])
29
+ /?
30
+ [0-9]{3}
31
+ (?<check>[0-9])?
32
+ \z
33
+ }x
34
+ private_constant :MATCHER_V1
35
+
36
+ MATCHER_V2 = %r{
37
+ \A
38
+ [0-9]{10}
39
+ \z
40
+ }x
41
+ private_constant :MATCHER_V2
42
+
43
+ # rubocop:disable Metrics/MethodLength
44
+ def valid_v1?
45
+ match = MATCHER_V1.match(tin)
46
+ return false unless match
47
+
48
+ year = match[:year].to_i
49
+ return false if year >= 54 && match[:check].nil?
50
+
51
+ if birth_date
52
+ month = match[:month].to_i
53
+ month -= 50 if month > 50
54
+
55
+ tin_date = date("#{birth_century}#{year}", month, match[:day])
56
+ return false if tin_date != birth_date
57
+ end
58
+
59
+ true
60
+ end
61
+ # rubocop:enable Metrics/MethodLength
62
+
63
+ def valid_v2? = MATCHER_V2.match?(tin)
64
+
65
+ def birth_century = birth_date.year.to_s[..1]
66
+ end
67
+ end
@@ -0,0 +1,38 @@
1
+ # frozen_string_literal: true
2
+
3
+ module TinValid
4
+ class SloveniaTin
5
+ def initialize(tin:)
6
+ @tin = tin
7
+ end
8
+
9
+ attr_reader :tin
10
+
11
+ def valid?
12
+ return false unless /\A[1-9][0-9]{7}\z/.match?(tin)
13
+
14
+ tin[-1].to_i == check
15
+ end
16
+
17
+ private
18
+
19
+ def check
20
+ # Multiply the values of each position by the corresponding weight:
21
+ weights =
22
+ 8
23
+ .downto(2)
24
+ .each_with_index
25
+ .map { |weight, index| weight * tin[index].to_i }
26
+
27
+ # 2. Add up the results of the above multiplications;
28
+ sum = weights.sum
29
+
30
+ # 3. Get modulo 11 of the result of the previous addition;
31
+ remainder = sum % 11
32
+
33
+ # 4. Check digit = 11 - remainder. If result = 10, Check digit = 0.
34
+ digit = 11 - remainder
35
+ digit == 10 ? 0 : digit
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,51 @@
1
+ # frozen_string_literal: true
2
+
3
+ module TinValid
4
+ class SpainTin
5
+ def initialize(tin:)
6
+ @tin = tin
7
+ end
8
+
9
+ attr_reader :tin
10
+
11
+ def valid?
12
+ valid_v1? || valid_v2?
13
+ end
14
+
15
+ private
16
+
17
+ def valid_v1?
18
+ return false unless /\A[0-9]{1,8}[A-Z]\z/.match?(tin)
19
+
20
+ tin[-1] == check_letter(tin)
21
+ end
22
+
23
+ def valid_v2?
24
+ return false unless /\A[XYZKLM][0-9]{7}[A-Z]\z/.match?(tin)
25
+
26
+ tin[-1] == check_v2
27
+ end
28
+
29
+ def check_v2
30
+ # 0. Replace the leading letter by the corresponding digit and concatenate
31
+ # the result with the other characters:
32
+ digit =
33
+ case tin[0]
34
+ when "X", "K", "L", "M" then 0
35
+ when "Y" then 1
36
+ when "Z" then 2
37
+ end
38
+
39
+ check_letter("#{digit}#{tin[1..]}")
40
+ end
41
+
42
+ def check_letter(code)
43
+ # 1. Take the remainder of modulo 23 of the 8 first characters;
44
+ remainder = code[..-2].to_i % 23
45
+
46
+ # 2. Add 1 to the remainder of operation 1;
47
+ # 3. The check letter corresponds to this figure in the table below:
48
+ "TRWAGMYFPDXBNJZSQVHLCKE"[remainder]
49
+ end
50
+ end
51
+ end
@@ -1,11 +1,16 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module TinValid
4
- class SwedenTin < Data.define(:tin, :birth_date)
4
+ class SwedenTin
5
+ include TinValid::Helpers
6
+
5
7
  def initialize(tin:, birth_date: nil)
6
- super
8
+ @tin = tin
9
+ @birth_date = birth_date
7
10
  end
8
11
 
12
+ attr_reader :tin, :birth_date
13
+
9
14
  def valid?
10
15
  VERSIONS.any? do |matcher|
11
16
  match = matcher.match(tin)
@@ -106,12 +111,5 @@ module TinValid
106
111
  date("20#{year}", month, day)
107
112
  end
108
113
  end
109
-
110
- def date(year, month, day)
111
- found_date = Date.new(year.to_i, month.to_i, day.to_i)
112
- found_date if found_date < Date.today
113
- rescue Date::Error
114
- nil
115
- end
116
114
  end
117
115
  end
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ module TinValid
4
+ class UnitedKingdomTin
5
+ def initialize(tin:)
6
+ @tin = tin
7
+ end
8
+
9
+ attr_reader :tin
10
+
11
+ def valid?
12
+ valid_v1? || valid_v2?
13
+ end
14
+
15
+ private
16
+
17
+ def valid_v1?
18
+ return false if %w[1234567890 0000000000].include?(tin)
19
+
20
+ /\A[0-9]{10}\z/.match?(tin)
21
+ end
22
+
23
+ def valid_v2?
24
+ return false unless /\A[A-Z]{2}[0-9]{6}[A-D]?\z/.match?(tin)
25
+ return false if %w[D F I Q U V].include?(tin[0])
26
+ return false if %w[D F I Q O U V].include?(tin[1])
27
+ return false if %w[GB NK TN ZZ].include?(tin[0..1])
28
+
29
+ true
30
+ end
31
+ end
32
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module TinValid
4
- VERSION = "0.1.1"
4
+ VERSION = "1.1.0"
5
5
  end
data/lib/tin_valid.rb CHANGED
@@ -2,6 +2,7 @@
2
2
 
3
3
  require "date"
4
4
  require_relative "tin_valid/version"
5
+ require_relative "tin_valid/helpers"
5
6
  require_relative "tin_valid/austria_tin"
6
7
  require_relative "tin_valid/belgium_tin"
7
8
  require_relative "tin_valid/bulgaria_tin"
@@ -10,10 +11,25 @@ require_relative "tin_valid/cyprus_tin"
10
11
  require_relative "tin_valid/czechia_tin"
11
12
  require_relative "tin_valid/denmark_tin"
12
13
  require_relative "tin_valid/estonia_tin"
14
+ require_relative "tin_valid/finland_tin"
15
+ require_relative "tin_valid/france_tin"
13
16
  require_relative "tin_valid/germany_tin"
14
17
  require_relative "tin_valid/greece_tin"
15
18
  require_relative "tin_valid/hungary_tin"
16
19
  require_relative "tin_valid/ireland_tin"
20
+ require_relative "tin_valid/italy_tin"
21
+ require_relative "tin_valid/latvia_tin"
22
+ require_relative "tin_valid/lithuania_tin"
23
+ require_relative "tin_valid/luxembourg_tin"
24
+ require_relative "tin_valid/malta_tin"
25
+ require_relative "tin_valid/netherlands_tin"
26
+ require_relative "tin_valid/poland_tin"
27
+ require_relative "tin_valid/portugal_tin"
28
+ require_relative "tin_valid/romania_tin"
29
+ require_relative "tin_valid/slovakia_tin"
30
+ require_relative "tin_valid/slovenia_tin"
31
+ require_relative "tin_valid/spain_tin"
17
32
  require_relative "tin_valid/sweden_tin"
33
+ require_relative "tin_valid/united_kingdom_tin"
18
34
 
19
35
  module TinValid; end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: tin_valid
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 1.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sunny Ripert
8
8
  bindir: exe
9
9
  cert_chain: []
10
- date: 2025-04-15 00:00:00.000000000 Z
10
+ date: 2025-04-18 00:00:00.000000000 Z
11
11
  dependencies: []
12
12
  email:
13
13
  - sunny@sunfox.org
@@ -31,11 +31,27 @@ files:
31
31
  - lib/tin_valid/czechia_tin.rb
32
32
  - lib/tin_valid/denmark_tin.rb
33
33
  - lib/tin_valid/estonia_tin.rb
34
+ - lib/tin_valid/finland_tin.rb
35
+ - lib/tin_valid/france_tin.rb
34
36
  - lib/tin_valid/germany_tin.rb
35
37
  - lib/tin_valid/greece_tin.rb
38
+ - lib/tin_valid/helpers.rb
36
39
  - lib/tin_valid/hungary_tin.rb
37
40
  - lib/tin_valid/ireland_tin.rb
41
+ - lib/tin_valid/italy_tin.rb
42
+ - lib/tin_valid/latvia_tin.rb
43
+ - lib/tin_valid/lithuania_tin.rb
44
+ - lib/tin_valid/luxembourg_tin.rb
45
+ - lib/tin_valid/malta_tin.rb
46
+ - lib/tin_valid/netherlands_tin.rb
47
+ - lib/tin_valid/poland_tin.rb
48
+ - lib/tin_valid/portugal_tin.rb
49
+ - lib/tin_valid/romania_tin.rb
50
+ - lib/tin_valid/slovakia_tin.rb
51
+ - lib/tin_valid/slovenia_tin.rb
52
+ - lib/tin_valid/spain_tin.rb
38
53
  - lib/tin_valid/sweden_tin.rb
54
+ - lib/tin_valid/united_kingdom_tin.rb
39
55
  - lib/tin_valid/version.rb
40
56
  - sig/tin_valid.rbs
41
57
  homepage: https://github.com/cults/tin_valid