tin_valid 0.1.0 → 0.1.1
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 +4 -4
- data/CHANGELOG.md +21 -1
- data/README.md +23 -15
- data/lib/tin_valid/austria_tin.rb +19 -6
- data/lib/tin_valid/germany_tin.rb +66 -0
- data/lib/tin_valid/greece_tin.rb +9 -0
- data/lib/tin_valid/hungary_tin.rb +25 -0
- data/lib/tin_valid/ireland_tin.rb +50 -0
- data/lib/tin_valid/version.rb +1 -1
- data/lib/tin_valid.rb +5 -4
- metadata +6 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b248c0be6699ce56b48b082c320833ff8cb5594a62762d298ea66315d8d7555b
|
4
|
+
data.tar.gz: a04549a7599fbadd881f1f905e2c13235d83a3e1d4b7bd8d79dc16393cd18465
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 608e79cfe16d11cd236c02a4b5dffa9062a4b26b0f8816c2e9a9da350471917a5cc7ac6802202223ec6936f82cc0f91f9b820118a9c56868b2c6c4a9eaa8f67f
|
7
|
+
data.tar.gz: a17c2624d59049524fbeb5b8adec5263dd6c4009d7bb90c594ad01c499c990a6784515a195bbd3a16148278c32f524b71067b6f0095020dccd24ae5a65987da4
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,25 @@
|
|
1
1
|
## [Unreleased]
|
2
2
|
|
3
|
+
## [0.1.1] - 2025-04-15
|
4
|
+
|
5
|
+
Features:
|
6
|
+
- Add Germany 🇩🇪
|
7
|
+
- Add Greece 🇬🇷
|
8
|
+
- Add Hungary 🇭🇺
|
9
|
+
- Add Ireland 🇮🇪
|
10
|
+
- Add #normalized to Austria 🇦🇹
|
11
|
+
|
3
12
|
## [0.1.0] - 2025-04-14
|
4
13
|
|
5
|
-
- Initial release
|
14
|
+
- Initial release with:
|
15
|
+
- Austria 🇦🇹
|
16
|
+
- Belgium 🇧🇪
|
17
|
+
- Bulgaria 🇧🇬
|
18
|
+
- Croatia 🇭🇷
|
19
|
+
- Cyprus 🇨🇾
|
20
|
+
- Czechia 🇨🇿
|
21
|
+
- Denmark 🇩🇰
|
22
|
+
- Estonia 🇪🇪
|
23
|
+
- Germany 🇩🇪
|
24
|
+
- Greece 🇬🇷
|
25
|
+
- Sweden 🇸🇪
|
data/README.md
CHANGED
@@ -1,20 +1,27 @@
|
|
1
|
-
# TinValid
|
1
|
+
# TinValid 🇪🇺
|
2
2
|
|
3
3
|
Validate Tax Identification Numbers (TINs) for the following European countries:
|
4
4
|
|
5
|
-
- Austria
|
6
|
-
- Belgium
|
7
|
-
- Bulgaria
|
8
|
-
- Croatia
|
9
|
-
- Cyprus
|
10
|
-
- Czechia
|
11
|
-
- Denmark
|
12
|
-
- Estonia
|
13
|
-
-
|
5
|
+
- Austria 🇦🇹
|
6
|
+
- Belgium 🇧🇪
|
7
|
+
- Bulgaria 🇧🇬
|
8
|
+
- Croatia 🇭🇷
|
9
|
+
- Cyprus 🇨🇾
|
10
|
+
- Czechia 🇨🇿
|
11
|
+
- Denmark 🇩🇰
|
12
|
+
- Estonia 🇪🇪
|
13
|
+
- Germany 🇩🇪
|
14
|
+
- Greece 🇬🇷
|
15
|
+
- Hungary 🇭🇺
|
16
|
+
- Ireland 🇮🇪
|
17
|
+
- Sweden 🇸🇪
|
18
|
+
|
19
|
+
See also the [descriptions of the structure provided by the European
|
20
|
+
Union](https://taxation-customs.ec.europa.eu/online-services/online-services-and-databases-taxation/taxpayer-identification-number-tin_en).
|
14
21
|
|
15
22
|
## Installation
|
16
23
|
|
17
|
-
|
24
|
+
Add the gem to your application’s Gemfile by executing:
|
18
25
|
|
19
26
|
```bash
|
20
27
|
bundle add tin_valid
|
@@ -31,7 +38,8 @@ gem install tin_valid
|
|
31
38
|
|
32
39
|
```rb
|
33
40
|
# Austria
|
34
|
-
TinValid::AustriaTin.new(tin: "
|
41
|
+
TinValid::AustriaTin.new(tin: "93-173/6581").valid? # => true
|
42
|
+
TinValid::AustriaTin.new(tin: "93-173/6581").normalized # => "931736581"
|
35
43
|
|
36
44
|
# Belgium
|
37
45
|
# Optional birth_date
|
@@ -80,10 +88,10 @@ git commits and the created tag, and push the `.gem` file to
|
|
80
88
|
## Contributing
|
81
89
|
|
82
90
|
Bug reports and pull requests are welcome on GitHub at
|
83
|
-
https://github.com/
|
91
|
+
https://github.com/cults/tin_valid. This project is intended to be a safe,
|
84
92
|
welcoming space for collaboration, and contributors are expected to adhere to
|
85
93
|
the
|
86
|
-
[code of conduct](https://github.com/
|
94
|
+
[code of conduct](https://github.com/cults/tin_valid/blob/main/CODE_OF_CONDUCT.md).
|
87
95
|
|
88
96
|
## License
|
89
97
|
|
@@ -94,4 +102,4 @@ The gem is available as open source under the terms of the
|
|
94
102
|
|
95
103
|
Everyone interacting in the TinValid project's codebases, issue trackers, chat
|
96
104
|
rooms and mailing lists is expected to follow the
|
97
|
-
[code of conduct](https://github.com/
|
105
|
+
[code of conduct](https://github.com/cults/tin_valid/blob/main/CODE_OF_CONDUCT.md).
|
@@ -1,15 +1,28 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module TinValid
|
4
|
-
class AustriaTin
|
4
|
+
class AustriaTin
|
5
|
+
def initialize(tin:)
|
6
|
+
@tin = tin
|
7
|
+
end
|
8
|
+
|
9
|
+
attr_reader :tin
|
10
|
+
|
5
11
|
def valid?
|
6
|
-
return false unless
|
12
|
+
return false unless MATCHER.match?(normalized)
|
7
13
|
|
8
|
-
|
14
|
+
normalized[-1] == check
|
15
|
+
end
|
16
|
+
|
17
|
+
def normalized
|
18
|
+
@normalized ||= tin.to_s.strip.tr("-/", "")
|
9
19
|
end
|
10
20
|
|
11
21
|
private
|
12
22
|
|
23
|
+
MATCHER = %r{\A[0-9]{2}-?[0-9]{3}/?[0-9]{4}\z}
|
24
|
+
private_constant :MATCHER
|
25
|
+
|
13
26
|
# rubocop:disable Metrics/AbcSize
|
14
27
|
def check
|
15
28
|
# 1. Multiply the values of each position by the corresponding weight:
|
@@ -22,10 +35,10 @@ module TinValid
|
|
22
35
|
# - C7: 1
|
23
36
|
# - C8: 2
|
24
37
|
values_by_weight =
|
25
|
-
|
26
|
-
.chars
|
38
|
+
normalized
|
39
|
+
.chars[..-2]
|
27
40
|
.each_with_index
|
28
|
-
.map { |n, i| n.to_i * (i.even? ?
|
41
|
+
.map { |n, i| n.to_i * (i.even? ? 1 : 2) }
|
29
42
|
|
30
43
|
# 2. If the product of a doubling operation is > 9, sum the digits of the
|
31
44
|
# product;
|
@@ -0,0 +1,66 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module TinValid
|
4
|
+
class GermanyTin < Data.define(:tin)
|
5
|
+
def valid?
|
6
|
+
valid_v1? || valid_v2?
|
7
|
+
end
|
8
|
+
|
9
|
+
private
|
10
|
+
|
11
|
+
def valid_v1?
|
12
|
+
# 1. 13 characters
|
13
|
+
# 2. Only digits
|
14
|
+
# 3. C5 is a 0
|
15
|
+
/\A[0-9]{4}0[0-9]{8}\z/.match?(tin)
|
16
|
+
end
|
17
|
+
|
18
|
+
# rubocop:disable Metrics/AbcSize
|
19
|
+
def valid_v2?
|
20
|
+
# C1: Must never be 0.
|
21
|
+
return false unless /\A[1-9][0-9]{10}\z/.match?(tin)
|
22
|
+
|
23
|
+
# C1-C10: One and only one mandatory duplicate or triple value:
|
24
|
+
# - One of the first ten digits is used twice (the recurrent digits do
|
25
|
+
# not have to be located at subsequent positions but they can be);
|
26
|
+
# - One of the first ten digits is used tree times (only two recurrent
|
27
|
+
# digits are allowed to be one after another).
|
28
|
+
consecutive_chars =
|
29
|
+
tin[..-2]
|
30
|
+
.chars
|
31
|
+
.group_by(&:itself)
|
32
|
+
.select { |_, chars| chars.size > 1 }
|
33
|
+
|
34
|
+
return false if consecutive_chars.size != 1
|
35
|
+
return false if consecutive_chars.first.last.size > 3
|
36
|
+
|
37
|
+
tin[-1].to_i == check_v2
|
38
|
+
end
|
39
|
+
# rubocop:enable Metrics/AbcSize
|
40
|
+
|
41
|
+
def check_v2
|
42
|
+
# 1. Initialize the variable X to 10.
|
43
|
+
y = tin[..-2].chars.inject(10) do |x, char|
|
44
|
+
# 2. Take C1 + X modulo 10. If result is 0, result is 10;
|
45
|
+
result = (char.to_i + x) % 10
|
46
|
+
result = 10 if result == 0
|
47
|
+
|
48
|
+
# 3. Multiply the result by 2;
|
49
|
+
result *= 2
|
50
|
+
|
51
|
+
# 4. Take modulo 11 of the result. Update the value of variable X with the result of this operation;
|
52
|
+
x = result % 11
|
53
|
+
|
54
|
+
# 5. Take C2 + X modulo 10. If result is 0, result is 10;
|
55
|
+
# 6. Multiply the result by 2;
|
56
|
+
# 7. Take modulo 11 of the result. Update the value of variable X with the result of this operation;
|
57
|
+
# 8. Apply steps 5, 6 and 7 in an analogue way for digits C3 to C10. Consider that last value called Y;
|
58
|
+
x
|
59
|
+
end
|
60
|
+
|
61
|
+
# 9. 11 - Y = check digit. If check digit = 10, replace it by 0.
|
62
|
+
check = 11 - y
|
63
|
+
check == 10 ? 0 : check
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module TinValid
|
4
|
+
class HungaryTin < Data.define(:tin)
|
5
|
+
def valid?
|
6
|
+
return false unless /\A8[0-9]{9}\z/.match?(tin)
|
7
|
+
|
8
|
+
tin[-1].to_i == check
|
9
|
+
end
|
10
|
+
|
11
|
+
private
|
12
|
+
|
13
|
+
def check
|
14
|
+
tin[..-2].chars
|
15
|
+
|
16
|
+
# 1. Multiply the values of each position by the corresponding weight:
|
17
|
+
# 2. Add up the results of the above multiplications;
|
18
|
+
result = (1..9).each_with_index.sum { |num, i| num * tin[i].to_i }
|
19
|
+
|
20
|
+
# 3. Get modulo 11 of the result of the previous addition;
|
21
|
+
# 4. Check digit = remainder.
|
22
|
+
result % 11
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module TinValid
|
4
|
+
class IrelandTin < Data.define(:tin)
|
5
|
+
def valid?
|
6
|
+
/\A[0-9]{7}[A-W][A-IW]?\z/.match?(tin) &&
|
7
|
+
tin.chars[7] == check
|
8
|
+
end
|
9
|
+
|
10
|
+
private
|
11
|
+
|
12
|
+
# rubocop:disable Metrics/AbcSize
|
13
|
+
def check
|
14
|
+
# 1. In reverse order, each digit is multiplied by a weight started at 2:
|
15
|
+
weights = 8.downto(2)
|
16
|
+
digits = weights.with_index.map { |weight, i| weight * tin.chars[i].to_i }
|
17
|
+
|
18
|
+
# 2. LetterToNumber(C9) is based on the following mapping:
|
19
|
+
# “A”=1, “B”=2, “C”=3, “D”=4, “E”=5, “F”=6, “G”=7, “H”=8, “I”=9
|
20
|
+
# A “W” or absence of character in position 9 is allocated a numeric
|
21
|
+
# value of 0.
|
22
|
+
digits.push letter_to_number(tin.chars[9 - 1]) * 9
|
23
|
+
|
24
|
+
# 3. Add up each result;
|
25
|
+
sum = digits.sum
|
26
|
+
|
27
|
+
# 4. The remainder of the modulo 23 indicates the character position on
|
28
|
+
# the alphabet according to the following mapping:
|
29
|
+
# 0=”W”, 1=”A”, 2=”B”, 3=”C”… 22=”V”
|
30
|
+
number_to_letter(sum % 23)
|
31
|
+
end
|
32
|
+
# rubocop:enable Metrics/AbcSize
|
33
|
+
|
34
|
+
def letter_to_number(letter)
|
35
|
+
return 0 if letter.nil?
|
36
|
+
|
37
|
+
case letter
|
38
|
+
in "W" then 0
|
39
|
+
in "A".."I" then letter.ord - 64
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def number_to_letter(number)
|
44
|
+
case number
|
45
|
+
in 0 then "W"
|
46
|
+
in 1..22 then (number + 64).chr
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
data/lib/tin_valid/version.rb
CHANGED
data/lib/tin_valid.rb
CHANGED
@@ -10,9 +10,10 @@ require_relative "tin_valid/cyprus_tin"
|
|
10
10
|
require_relative "tin_valid/czechia_tin"
|
11
11
|
require_relative "tin_valid/denmark_tin"
|
12
12
|
require_relative "tin_valid/estonia_tin"
|
13
|
+
require_relative "tin_valid/germany_tin"
|
14
|
+
require_relative "tin_valid/greece_tin"
|
15
|
+
require_relative "tin_valid/hungary_tin"
|
16
|
+
require_relative "tin_valid/ireland_tin"
|
13
17
|
require_relative "tin_valid/sweden_tin"
|
14
18
|
|
15
|
-
module TinValid
|
16
|
-
class Error < StandardError; end
|
17
|
-
# Your code goes here...
|
18
|
-
end
|
19
|
+
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.
|
4
|
+
version: 0.1.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Sunny Ripert
|
8
8
|
bindir: exe
|
9
9
|
cert_chain: []
|
10
|
-
date: 2025-04-
|
10
|
+
date: 2025-04-15 00:00:00.000000000 Z
|
11
11
|
dependencies: []
|
12
12
|
email:
|
13
13
|
- sunny@sunfox.org
|
@@ -31,6 +31,10 @@ 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/germany_tin.rb
|
35
|
+
- lib/tin_valid/greece_tin.rb
|
36
|
+
- lib/tin_valid/hungary_tin.rb
|
37
|
+
- lib/tin_valid/ireland_tin.rb
|
34
38
|
- lib/tin_valid/sweden_tin.rb
|
35
39
|
- lib/tin_valid/version.rb
|
36
40
|
- sig/tin_valid.rbs
|