tin_valid 1.0.0 → 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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c64b5917083db71c567a2b80c3edf35d58d32b07da94b9e0ced0e189a3bb4f13
4
- data.tar.gz: 9785af41b29fc7c335d1f7f062ed8ae217a421e145005a783bd56eeb43d75c5a
3
+ metadata.gz: 2a4dc099cefbd5653c35bb0a8d78061e7e9239a917f2f872e7036651c429c014
4
+ data.tar.gz: c540ebe0de3b7f4c69c65c2d05b0d2d67b1beca905e4ee2e99416b361d4991c9
5
5
  SHA512:
6
- metadata.gz: '097ef7fcbdeb7f95b0456fdcd930501f9da4eb85ddb9bc0a5a8e9996d58aa03939fe409d2a0ed7f0c25ae1bee786bcce19a3c079e91969b62839337d581f5d3a'
7
- data.tar.gz: e4bb19d3238b04228390f78e505375af8e695f2cb3060c518f6aa6e41b2b61db2f065fc483ade6a84f45213e05c90f55f76b4a18f36f54b1a0615f505bf08e05
6
+ metadata.gz: d34baae639710a1f82adc36eedce1bb6b961e7fbe3f2128d091b5c61f6956276dc047207d62ac46325577028e5db562a955a4603056d0096469ce48e7698adbf
7
+ data.tar.gz: 97e1d3b264372400e0575a30d15087d53bb3220c49e2126a5aa24417407b806e8018e4bf26cef7e7ff8a1d749e74c907801a8b3e2ae52ddae85008394682ba28
data/CHANGELOG.md CHANGED
@@ -1,5 +1,15 @@
1
1
  ## [Unreleased]
2
2
 
3
+ ## [1.1.0] - 2025-04-18
4
+
5
+ Features:
6
+ - Add Finland 🇫🇮
7
+ - Add France 🇫🇷
8
+
9
+ Fixes:
10
+ - Test against clearly invalid codes 00000… and 123456…
11
+ - Check that all dates are in the past
12
+
3
13
  ## [1.0.0] - 2025-04-17
4
14
 
5
15
  Features:
data/README.md CHANGED
@@ -10,6 +10,8 @@ Validate Tax Identification Numbers (TINs) for the following European countries:
10
10
  - Czechia 🇨🇿
11
11
  - Denmark 🇩🇰
12
12
  - Estonia 🇪🇪
13
+ - Finland 🇫🇮
14
+ - France 🇫🇷
13
15
  - Germany 🇩🇪
14
16
  - Greece 🇬🇷
15
17
  - Hungary 🇭🇺
@@ -80,6 +82,13 @@ TinValid::DenmarkTin.new(tin: "…", birth_date: Date.new(…)).valid?
80
82
  # Optional birth_date
81
83
  TinValid::EstoniaTin.new(tin: "…", birth_date: Date.new(…)).valid?
82
84
 
85
+ # Finland
86
+ # Optional birth_date
87
+ TinValid::FinlandTin.new(tin: "…", birth_date: Date.new(…)).valid?
88
+
89
+ # France
90
+ TinValid::FranceTin.new(tin: "…").valid?
91
+
83
92
  # Germany
84
93
  TinValid::GermanyTin.new(tin: "…").valid?
85
94
 
@@ -10,6 +10,7 @@ module TinValid
10
10
 
11
11
  def valid?
12
12
  return false unless MATCHER.match?(normalized)
13
+ return false if %w[000000000 123456789].include?(normalized)
13
14
 
14
15
  normalized[-1] == check
15
16
  end
@@ -2,6 +2,8 @@
2
2
 
3
3
  module TinValid
4
4
  class BelgiumTin
5
+ include TinValid::Helpers
6
+
5
7
  def initialize(tin:, birth_date: nil)
6
8
  @tin = tin
7
9
  @birth_date = birth_date
@@ -37,6 +39,15 @@ module TinValid
37
39
  def check = match[:check].to_i
38
40
 
39
41
  def valid_check?(year, month, day, number)
42
+ # A month (in the range 00...12, 00 is acceptable for person not born in
43
+ # Belgium and with an uncertain date of birth).
44
+ month = 1 if month == "00"
45
+
46
+ # A day of month (in the range 00...31 depending on month and year, 00 is
47
+ # acceptable for person not born in Belgium and with an uncertain date of
48
+ # birth).
49
+ day = 1 if day == "00"
50
+
40
51
  tin_date = date(year, month, day)
41
52
  return false if tin_date.nil?
42
53
  return false if birth_date && birth_date != tin_date
@@ -54,20 +65,5 @@ module TinValid
54
65
  #
55
66
  # 2. 97 - remainder of the previous division is the check number
56
67
  def digit_check(number) = 97 - (number.to_i % 97)
57
-
58
- def date(year, month, day)
59
- # A month (in the range 00...12, 00 is acceptable for person not born in
60
- # Belgium and with an uncertain date of birth).
61
- month = 1 if month == "00"
62
-
63
- # A day of month (in the range 00...31 depending on month and year, 00 is
64
- # acceptable for person not born in Belgium and with an uncertain date of
65
- # birth).
66
- day = 1 if day == "00"
67
-
68
- Date.new(year.to_i, month.to_i, day.to_i)
69
- rescue Date::Error
70
- nil
71
- end
72
68
  end
73
69
  end
@@ -1,11 +1,16 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module TinValid
4
- class BulgariaTin < Data.define(:tin, :birth_date)
4
+ class BulgariaTin
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
  match = MATCHER.match(tin)
11
16
  return false unless match
@@ -37,9 +42,9 @@ module TinValid
37
42
  day = day.to_i
38
43
 
39
44
  if birth_date.nil?
40
- past_date?("18#{year}", month - 20, day) ||
41
- past_date?("19#{year}", month, day) ||
42
- past_date?("20#{year}", month - 40, day)
45
+ date("18#{year}", month - 20, day) ||
46
+ date("19#{year}", month, day) ||
47
+ date("20#{year}", month - 40, day)
43
48
  elsif birth_year < 1900
44
49
  birth_date == date("18#{year}", month - 20, day)
45
50
  elsif birth_year < 2000
@@ -53,17 +58,6 @@ module TinValid
53
58
 
54
59
  def birth_year = birth_date.year
55
60
 
56
- def past_date?(year, month, day)
57
- found_date = date(year, month, day)
58
- found_date && found_date < Date.today
59
- end
60
-
61
- def date(year, month, day)
62
- Date.new(year.to_i, month.to_i, day.to_i)
63
- rescue Date::Error
64
- nil
65
- end
66
-
67
61
  def check
68
62
  weights = [2, 4, 8, 5, 10, 9, 7, 3, 6]
69
63
 
@@ -1,7 +1,13 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module TinValid
4
- class CroatiaTin < Data.define(:tin)
4
+ class CroatiaTin
5
+ def initialize(tin:)
6
+ @tin = tin
7
+ end
8
+
9
+ attr_reader :tin
10
+
5
11
  def valid?
6
12
  return false unless /\A[0-9]{11}\z/.match?(tin)
7
13
 
@@ -1,11 +1,14 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module TinValid
4
- class CyprusTin < Data.define(:tin, :kind)
4
+ class CyprusTin
5
5
  def initialize(tin:, kind: nil)
6
- super
6
+ @tin = tin
7
+ @kind = kind
7
8
  end
8
9
 
10
+ attr_reader :tin, :kind
11
+
9
12
  def valid?
10
13
  matcher.match?(tin) && check == tin[-1]
11
14
  end
@@ -1,11 +1,16 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module TinValid
4
- class CzechiaTin < Data.define(:tin, :birth_date)
4
+ class CzechiaTin
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? = valid_v1? || valid_v2?
10
15
 
11
16
  private
@@ -33,6 +38,7 @@ module TinValid
33
38
  def valid_v1?
34
39
  match = MATCHER_V1.match(tin)
35
40
  return false unless match
41
+ return false if tin == "000000000"
36
42
  return true if birth_date.nil?
37
43
  return false if year_of_birth >= 1954
38
44
 
@@ -46,11 +52,10 @@ module TinValid
46
52
  birth_date == date(year, month, match[:day])
47
53
  end
48
54
 
49
- # rubocop:disable Metrics/AbcSize
50
- # rubocop:disable Metrics/MethodLength
51
55
  def valid_v2?
52
56
  match = MATCHER_V2.match(tin)
53
57
  return false unless match
58
+ return false if tin == "0000000000"
54
59
  return true if birth_date.nil?
55
60
  return false if year_of_birth < 1954
56
61
 
@@ -59,30 +64,26 @@ module TinValid
59
64
  # 54 - 99 for people born between 1954 and 1999.
60
65
  year = "#{birth_century}#{match[:year]}"
61
66
 
62
- # Month (in the range 1...12 only for men) or month + 20 (in the range
63
- # 21…32 only for men) or month + 50 (in the range 51...62 only for women)
64
- # or month + 70 (in the range 71…82 only for women).
65
- month = match[:month].to_i
66
- if month > 70
67
- month -= 70
68
- elsif month > 50
69
- month -= 50
70
- elsif month > 20
71
- month -= 20
72
- end
73
-
74
- birth_date == date(year, month, match[:day])
67
+ birth_date == date(year, month_integer(match[:month]), match[:day])
75
68
  end
76
- # rubocop:enable Metrics/AbcSize
77
- # rubocop:enable Metrics/MethodLength
78
69
 
79
70
  def year_of_birth = birth_date&.year
80
71
  def birth_century = birth_date.strftime("%Y")[..1]
81
72
 
82
- def date(year, month, day)
83
- Date.new(year.to_i, month.to_i, day.to_i)
84
- rescue Date::Error
85
- nil
73
+ # Month (in the range 1...12 only for men) or month + 20 (in the range
74
+ # 21…32 only for men) or month + 50 (in the range 51...62 only for women)
75
+ # or month + 70 (in the range 71…82 only for women).
76
+ def month_integer(number)
77
+ number = number.to_i
78
+ if number > 70
79
+ number - 70
80
+ elsif number > 50
81
+ number - 50
82
+ elsif number > 20
83
+ number - 20
84
+ else
85
+ number
86
+ end
86
87
  end
87
88
  end
88
89
  end
@@ -1,14 +1,21 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module TinValid
4
- class DenmarkTin < Data.define(:tin, :birth_date)
4
+ class DenmarkTin
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
+
14
+ # rubocop:disable Metrics/AbcSize
9
15
  def valid?
10
16
  match = MATCHER.match(tin)
11
17
  return false unless match
18
+ return false if tin == "0000000000"
12
19
 
13
20
  if birth_date
14
21
  year = "#{birth_century}#{match[:year]}"
@@ -19,6 +26,7 @@ module TinValid
19
26
 
20
27
  match[:check].to_i == checksum
21
28
  end
29
+ # rubocop:enable Metrics/AbcSize
22
30
 
23
31
  private
24
32
 
@@ -38,12 +46,6 @@ module TinValid
38
46
  def birth_century = birth_date.strftime("%Y")[..1]
39
47
  def birth_year = birth_date.year
40
48
 
41
- def date(year, month, day)
42
- Date.new(year.to_i, month.to_i, day.to_i)
43
- rescue Date::Error
44
- nil
45
- end
46
-
47
49
  def checksum
48
50
  # 1. Multiply the values of each position by the corresponding weight:
49
51
  weights =
@@ -1,11 +1,16 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module TinValid
4
- class EstoniaTin < Data.define(:tin, :birth_date)
4
+ class EstoniaTin
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
  match = MATCHER.match(tin)
11
16
  return false unless match
@@ -36,12 +41,6 @@ module TinValid
36
41
  def birth_century = birth_date.strftime("%Y")[..1]
37
42
  def birth_year = birth_date.year
38
43
 
39
- def date(year, month, day)
40
- Date.new(year.to_i, month.to_i, day.to_i)
41
- rescue Date::Error
42
- nil
43
- end
44
-
45
44
  def checksum
46
45
  # 1. Multiply the values of each position by the corresponding weight:
47
46
  # 2. Add up the results of the above multiplications;
@@ -0,0 +1,71 @@
1
+ # frozen_string_literal: true
2
+
3
+ module TinValid
4
+ class FinlandTin
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
+ match = MATCHER.match(tin)
16
+ return false unless match
17
+
18
+ tin_date = date(
19
+ "#{tin_century(match[:century])}#{match[:year]}",
20
+ match[:month],
21
+ match[:day],
22
+ )
23
+ return false unless tin_date
24
+ return false if birth_date && birth_date != tin_date
25
+
26
+ tin[-1] == check
27
+ end
28
+
29
+ private
30
+
31
+ MATCHER = %r{
32
+ \A
33
+ (?<day>[0-3][0-9])
34
+ (?<month>[0-1][0-9])
35
+ (?<year>[0-9][0-9])
36
+ (?<century>[-+A-FU-Y])
37
+ [0-9]{3}
38
+ [0-9A-Z]
39
+ \z
40
+ }x
41
+ private_constant :MATCHER
42
+
43
+ def tin_century(character)
44
+ case character
45
+ when "+" then 18
46
+ when "-", "U", "V", "W", "X", "Y" then 19
47
+ else 20
48
+ end
49
+ end
50
+
51
+ def check
52
+ # 1. Concatenate C1, C2, C3, C4, C5, C6, C8, C9, C10
53
+ # (warning: C7 is not part of the check digit);
54
+ number = "#{tin[0..5]}#{tin[7..9]}".to_i
55
+
56
+ # 2. Calculate the modulo 31 of the abovementioned number;
57
+ remainder = number % 31
58
+
59
+ # 4. The result of calculating modulo 31 will give as a result a number,
60
+ # which will provide the check mark through the following table:
61
+ case remainder
62
+ when ..9 then remainder.to_s
63
+ when ..15 then (remainder + 55).chr
64
+ when 16 then "H"
65
+ when ..21 then (remainder + 57).chr
66
+ when 21 then "P"
67
+ else (remainder + 59).chr
68
+ end
69
+ end
70
+ end
71
+ end
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ module TinValid
4
+ class FranceTin
5
+ def initialize(tin:)
6
+ @tin = tin
7
+ end
8
+
9
+ attr_reader :tin
10
+
11
+ def valid?
12
+ return false unless /\A[0-3][0-9]{12}\z/.match?(tin)
13
+ return false if tin == "0000000000000"
14
+
15
+ tin[-3..].to_i == check
16
+ end
17
+
18
+ private
19
+
20
+ def check
21
+ # 1. Concatenate C1, C2, C3, C4, C5, C6, C7, C8, C9, C10;
22
+ # 2. Get modulo 511 of the result of the previous result;
23
+ # 3. Check digit = remainder if remainder < 100, C11 = 0
24
+ # (if remainder < 10, C11 = 0 and C12 = 0).
25
+ tin[..-4].to_i % 511
26
+ end
27
+ end
28
+ end
@@ -1,7 +1,13 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module TinValid
4
- class GermanyTin < Data.define(:tin)
4
+ class GermanyTin
5
+ def initialize(tin:)
6
+ @tin = tin
7
+ end
8
+
9
+ attr_reader :tin
10
+
5
11
  def valid?
6
12
  valid_v1? || valid_v2?
7
13
  end
@@ -12,7 +18,9 @@ module TinValid
12
18
  # 1. 13 characters
13
19
  # 2. Only digits
14
20
  # 3. C5 is a 0
15
- /\A[0-9]{4}0[0-9]{8}\z/.match?(tin)
21
+ return false unless /\A[0-9]{4}0[0-9]{8}\z/.match?(tin)
22
+
23
+ tin.to_i != 0
16
24
  end
17
25
 
18
26
  # rubocop:disable Metrics/AbcSize
@@ -1,9 +1,17 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module TinValid
4
- class GreeceTin < Data.define(:tin)
4
+ class GreeceTin
5
+ def initialize(tin:)
6
+ @tin = tin
7
+ end
8
+
9
+ attr_reader :tin
10
+
5
11
  def valid?
6
- /\A[0-9]{9}\z/.match?(tin)
12
+ return false unless /\A[0-9]{9}\z/.match?(tin)
13
+
14
+ tin != "000000000" && tin != "123456789"
7
15
  end
8
16
  end
9
17
  end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ module TinValid
4
+ module Helpers
5
+ private
6
+
7
+ def date(year, month, day)
8
+ found_date = Date.new(year.to_i, month.to_i, day.to_i)
9
+ found_date if found_date < Date.today
10
+ rescue Date::Error
11
+ nil
12
+ end
13
+ end
14
+ end
@@ -1,7 +1,13 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module TinValid
4
- class HungaryTin < Data.define(:tin)
4
+ class HungaryTin
5
+ def initialize(tin:)
6
+ @tin = tin
7
+ end
8
+
9
+ attr_reader :tin
10
+
5
11
  def valid?
6
12
  return false unless /\A8[0-9]{9}\z/.match?(tin)
7
13
 
@@ -1,7 +1,13 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module TinValid
4
- class IrelandTin < Data.define(:tin)
4
+ class IrelandTin
5
+ def initialize(tin:)
6
+ @tin = tin
7
+ end
8
+
9
+ attr_reader :tin
10
+
5
11
  def valid?
6
12
  /\A[0-9]{7}[A-W][A-IW]?\z/.match?(tin) &&
7
13
  tin.chars[7] == check
@@ -3,6 +3,8 @@
3
3
  module TinValid
4
4
  # rubocop:disable Metrics/ClassLength
5
5
  class ItalyTin
6
+ include TinValid::Helpers
7
+
6
8
  def initialize(tin:, birth_date: nil)
7
9
  @tin = tin
8
10
  @birth_date = birth_date
@@ -35,7 +37,7 @@ module TinValid
35
37
  if birth_date
36
38
  birth_date == date("#{birth_century}#{year}", month, day)
37
39
  else
38
- date?("19#{year}", month, day) || date?("20#{year}", month, day)
40
+ date("19#{year}", month, day) || date("20#{year}", month, day)
39
41
  end
40
42
  end
41
43
 
@@ -60,17 +62,6 @@ module TinValid
60
62
  string.chars.map { NUMERICAL_REPLACEMENTS.fetch(_1, _1) }.join.to_i
61
63
  end
62
64
 
63
- def date?(year, month, day)
64
- found_date = date(year, month, day)
65
- found_date && found_date < Date.today
66
- end
67
-
68
- def date(year, month, day)
69
- Date.new(year.to_i, month.to_i, day.to_i)
70
- rescue Date::Error
71
- nil
72
- end
73
-
74
65
  MATCHER = %r{
75
66
  \A
76
67
  [A-Z]{6}
@@ -1,11 +1,14 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module TinValid
4
- class LatviaTin < Data.define(:tin, :birth_date)
4
+ class LatviaTin
5
5
  def initialize(tin:, birth_date: nil)
6
- super
6
+ @tin = tin
7
+ @birth_date = birth_date
7
8
  end
8
9
 
10
+ attr_reader :tin, :birth_date
11
+
9
12
  def valid? = valid_v1? || valid_v2?
10
13
 
11
14
  private
@@ -35,6 +38,7 @@ module TinValid
35
38
  def valid_v1?
36
39
  match = MATCHER_V1.match(tin)
37
40
  return false unless match
41
+ return false if tin == "00000000000"
38
42
 
39
43
  if birth_date
40
44
  tin[..5] == birth_date.strftime("%d%m%y") &&
@@ -1,11 +1,14 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module TinValid
4
- class LithuaniaTin < Data.define(:tin, :birth_date)
4
+ class LithuaniaTin
5
5
  def initialize(tin:, birth_date: nil)
6
- super
6
+ @tin = tin
7
+ @birth_date = birth_date
7
8
  end
8
9
 
10
+ attr_reader :tin, :birth_date
11
+
9
12
  def valid?
10
13
  matcher = MATCHER.match(tin)
11
14
  return false unless matcher
@@ -1,11 +1,16 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module TinValid
4
- class LuxembourgTin < Data.define(:tin, :birth_date)
4
+ class LuxembourgTin
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
  match = MATCHER.match(tin)
11
16
  return false unless match
@@ -69,12 +74,6 @@ module TinValid
69
74
  checksum == 0
70
75
  end
71
76
 
72
- def date(year, month, day)
73
- Date.new(year.to_i, month.to_i, day.to_i)
74
- rescue Date::Error
75
- nil
76
- end
77
-
78
77
  def table_d(number_i, number_j) = TABLE_D.dig(number_i, number_j)
79
78
  def table_p(number_m, number_n) = TABLE_P.dig(number_m, number_n)
80
79
 
@@ -1,7 +1,13 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module TinValid
4
- class MaltaTin < Data.define(:tin)
4
+ class MaltaTin
5
+ def initialize(tin:)
6
+ @tin = tin
7
+ end
8
+
9
+ attr_reader :tin
10
+
5
11
  def valid? = valid_format_1? || valid_format_2?
6
12
 
7
13
  private
@@ -1,9 +1,16 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module TinValid
4
- class NetherlandsTin < Data.define(:tin)
4
+ class NetherlandsTin
5
+ def initialize(tin:)
6
+ @tin = tin
7
+ end
8
+
9
+ attr_reader :tin
10
+
5
11
  def valid?
6
12
  return false unless /\A[0-9]{9}\z/.match?(tin)
13
+ return false if tin == "000000000"
7
14
 
8
15
  tin[-1].to_i == check
9
16
  end
@@ -1,11 +1,16 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module TinValid
4
- class PolandTin < Data.define(:tin, :birth_date)
4
+ class PolandTin
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? = valid_v1? || valid_v2?
10
15
 
11
16
  private
@@ -25,6 +30,7 @@ module TinValid
25
30
 
26
31
  def valid_v1?
27
32
  return false unless MATCHER_V1.match?(tin)
33
+ return false if tin == "0000000000"
28
34
 
29
35
  tin[-1].to_i == check
30
36
  end
@@ -32,6 +38,7 @@ module TinValid
32
38
  def valid_v2?
33
39
  match = MATCHER_V2.match(tin)
34
40
  return false unless match
41
+ return false if tin == "00000000000"
35
42
  return true unless birth_date
36
43
 
37
44
  tin_date = date(
@@ -68,11 +75,5 @@ module TinValid
68
75
  else 0
69
76
  end
70
77
  end
71
-
72
- def date(year, month, day)
73
- Date.new(year.to_i, month.to_i, day.to_i)
74
- rescue Date::Error
75
- nil
76
- end
77
78
  end
78
79
  end
@@ -1,9 +1,17 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module TinValid
4
- class PortugalTin < Data.define(:tin)
4
+ class PortugalTin
5
+ def initialize(tin:)
6
+ @tin = tin
7
+ end
8
+
9
+ attr_reader :tin
10
+
5
11
  def valid?
6
12
  return false unless /\A[0-9]{9}\z/.match?(tin)
13
+ return false if tin == "000000000"
14
+ return false if tin == "123456789"
7
15
 
8
16
  tin[-1].to_i == check
9
17
  end
@@ -1,11 +1,16 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module TinValid
4
- class RomaniaTin < Data.define(:tin, :birth_date)
4
+ class RomaniaTin
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? = valid_v1? || valid_v2?
10
15
 
11
16
  private
@@ -74,11 +79,5 @@ module TinValid
74
79
  when 5..6 then 20
75
80
  end
76
81
  end
77
-
78
- def date(year, month, day)
79
- Date.new(year.to_i, month.to_i, day.to_i)
80
- rescue Date::Error
81
- nil
82
- end
83
82
  end
84
83
  end
@@ -1,12 +1,21 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module TinValid
4
- class SlovakiaTin < Data.define(:tin, :birth_date)
4
+ class SlovakiaTin
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
 
9
- def valid? = valid_v2? || valid_v1?
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
10
19
 
11
20
  def normalized = tin.tr("/", "")
12
21
 
@@ -54,11 +63,5 @@ module TinValid
54
63
  def valid_v2? = MATCHER_V2.match?(tin)
55
64
 
56
65
  def birth_century = birth_date.year.to_s[..1]
57
-
58
- def date(year, month, day)
59
- Date.new(year.to_i, month.to_i, day.to_i)
60
- rescue Date::Error
61
- nil
62
- end
63
66
  end
64
67
  end
@@ -1,7 +1,13 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module TinValid
4
- class SloveniaTin < Data.define(:tin)
4
+ class SloveniaTin
5
+ def initialize(tin:)
6
+ @tin = tin
7
+ end
8
+
9
+ attr_reader :tin
10
+
5
11
  def valid?
6
12
  return false unless /\A[1-9][0-9]{7}\z/.match?(tin)
7
13
 
@@ -1,7 +1,13 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module TinValid
4
- class SpainTin < Data.define(:tin)
4
+ class SpainTin
5
+ def initialize(tin:)
6
+ @tin = tin
7
+ end
8
+
9
+ attr_reader :tin
10
+
5
11
  def valid?
6
12
  valid_v1? || valid_v2?
7
13
  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
@@ -1,14 +1,24 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module TinValid
4
- class UnitedKingdomTin < Data.define(:tin)
4
+ class UnitedKingdomTin
5
+ def initialize(tin:)
6
+ @tin = tin
7
+ end
8
+
9
+ attr_reader :tin
10
+
5
11
  def valid?
6
12
  valid_v1? || valid_v2?
7
13
  end
8
14
 
9
15
  private
10
16
 
11
- def valid_v1? = /\A[0-9]{10}\z/.match?(tin)
17
+ def valid_v1?
18
+ return false if %w[1234567890 0000000000].include?(tin)
19
+
20
+ /\A[0-9]{10}\z/.match?(tin)
21
+ end
12
22
 
13
23
  def valid_v2?
14
24
  return false unless /\A[A-Z]{2}[0-9]{6}[A-D]?\z/.match?(tin)
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module TinValid
4
- VERSION = "1.0.0"
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,6 +11,8 @@ 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"
@@ -26,7 +29,7 @@ require_relative "tin_valid/romania_tin"
26
29
  require_relative "tin_valid/slovakia_tin"
27
30
  require_relative "tin_valid/slovenia_tin"
28
31
  require_relative "tin_valid/spain_tin"
29
- require_relative "tin_valid/united_kingdom_tin"
30
32
  require_relative "tin_valid/sweden_tin"
33
+ require_relative "tin_valid/united_kingdom_tin"
31
34
 
32
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: 1.0.0
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-17 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,8 +31,11 @@ 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
38
41
  - lib/tin_valid/italy_tin.rb