itax_code 2.0.0 → 2.0.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/workflows/lint.yml +2 -1
- data/.github/workflows/release.yml +27 -5
- data/.github/workflows/test.yml +24 -4
- data/.rubocop.yml +1 -0
- data/CHANGELOG.md +33 -0
- data/Gemfile +1 -0
- data/README.md +2 -3
- data/itax_code.gemspec +0 -1
- data/lib/itax_code/data/cities.csv +211 -164
- data/lib/itax_code/encoder.rb +6 -7
- data/lib/itax_code/error.rb +20 -0
- data/lib/itax_code/parser.rb +6 -10
- data/lib/itax_code/transliterator.rb +211 -0
- data/lib/itax_code/utils.rb +22 -5
- data/lib/itax_code/version.rb +1 -1
- data/lib/itax_code.rb +1 -4
- data/rakelib/cities.rake +1 -1
- metadata +5 -18
- data/.travis.yml +0 -6
data/lib/itax_code/encoder.rb
CHANGED
@@ -14,8 +14,6 @@ module ItaxCode
|
|
14
14
|
#
|
15
15
|
# @return [String] The encoded tax code
|
16
16
|
class Encoder
|
17
|
-
MissingDataError = Class.new(StandardError)
|
18
|
-
|
19
17
|
# @param [Hash] data The user attributes
|
20
18
|
# @param [Utils] utils
|
21
19
|
#
|
@@ -25,6 +23,8 @@ module ItaxCode
|
|
25
23
|
# @option data [String, Date] :birthdate The user birthdate
|
26
24
|
# @option data [String] :birthplace The user birthplace
|
27
25
|
def initialize(data = {}, utils = Utils.new)
|
26
|
+
@utils = utils
|
27
|
+
|
28
28
|
@surname = data[:surname]
|
29
29
|
@name = data[:name]
|
30
30
|
@gender = data[:gender]&.upcase
|
@@ -33,7 +33,6 @@ module ItaxCode
|
|
33
33
|
validate_data_presence!
|
34
34
|
|
35
35
|
@birthdate = parse_birthdate!
|
36
|
-
@utils = utils
|
37
36
|
end
|
38
37
|
|
39
38
|
# Computes the tax code from its components.
|
@@ -81,8 +80,8 @@ module ItaxCode
|
|
81
80
|
place_slug = utils.slugged(birthplace)
|
82
81
|
place_item = src.find { |i| place_slug == utils.slugged(i[lookup_key]) }
|
83
82
|
|
84
|
-
code = place_item
|
85
|
-
return code if
|
83
|
+
code = place_item&.[]("code")
|
84
|
+
return code if utils.present?(code)
|
86
85
|
raise MissingDataError, "no code found for #{birthplace}" if stop
|
87
86
|
|
88
87
|
encode_birthplace(utils.countries, stop: true)
|
@@ -90,7 +89,7 @@ module ItaxCode
|
|
90
89
|
|
91
90
|
def validate_data_presence!
|
92
91
|
instance_variables.each do |ivar|
|
93
|
-
next if instance_variable_get(ivar)
|
92
|
+
next if utils.present?(instance_variable_get(ivar))
|
94
93
|
|
95
94
|
raise MissingDataError, "missing #{ivar} value"
|
96
95
|
end
|
@@ -99,7 +98,7 @@ module ItaxCode
|
|
99
98
|
def parse_birthdate!
|
100
99
|
Date.parse(birthdate)
|
101
100
|
rescue StandardError
|
102
|
-
raise
|
101
|
+
raise InvalidBirthdateError, "#{birthdate} is not a valid date"
|
103
102
|
end
|
104
103
|
end
|
105
104
|
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ItaxCode
|
4
|
+
Error = Class.new(StandardError)
|
5
|
+
|
6
|
+
class Encoder
|
7
|
+
Error = Class.new(Error)
|
8
|
+
|
9
|
+
InvalidBirthdateError = Class.new(Error)
|
10
|
+
MissingDataError = Class.new(Error)
|
11
|
+
end
|
12
|
+
|
13
|
+
class Parser
|
14
|
+
Error = Class.new(Error)
|
15
|
+
|
16
|
+
InvalidControlInternalNumberError = Class.new(Error)
|
17
|
+
InvalidTaxCodeError = Class.new(Error)
|
18
|
+
NoTaxCodeError = Class.new(Error)
|
19
|
+
end
|
20
|
+
end
|
data/lib/itax_code/parser.rb
CHANGED
@@ -11,11 +11,6 @@ module ItaxCode
|
|
11
11
|
#
|
12
12
|
# @return [Hash] The parsed tax code
|
13
13
|
class Parser
|
14
|
-
Error = Class.new(StandardError)
|
15
|
-
NoTaxCodeError = Class.new(Error)
|
16
|
-
InvalidControlInternalNumberError = Class.new(Error)
|
17
|
-
InvalidTaxCodeError = Class.new(Error)
|
18
|
-
|
19
14
|
LENGTH = 16
|
20
15
|
|
21
16
|
# @param [String] tax_code
|
@@ -24,7 +19,7 @@ module ItaxCode
|
|
24
19
|
@tax_code = tax_code&.upcase
|
25
20
|
@utils = utils
|
26
21
|
|
27
|
-
raise NoTaxCodeError if @
|
22
|
+
raise NoTaxCodeError if @utils.blank?(@tax_code)
|
28
23
|
raise InvalidTaxCodeError if @tax_code.length != LENGTH
|
29
24
|
raise InvalidControlInternalNumberError if raw[:cin] != @utils.encode_cin(@tax_code)
|
30
25
|
end
|
@@ -61,7 +56,7 @@ module ItaxCode
|
|
61
56
|
end
|
62
57
|
|
63
58
|
def raw_matches
|
64
|
-
@raw_matches ||= tax_code.scan(utils.
|
59
|
+
@raw_matches ||= tax_code.scan(utils.tax_code_sections_regex).flatten
|
65
60
|
end
|
66
61
|
|
67
62
|
def gender
|
@@ -73,8 +68,9 @@ module ItaxCode
|
|
73
68
|
# value could be wrong. E.g. a person born on 1920 would have birthdate_year = 20 meaning
|
74
69
|
# that both 1920 and 2020 could be valid born years.
|
75
70
|
def year
|
76
|
-
|
77
|
-
val
|
71
|
+
current_year = Date.today.year
|
72
|
+
val = (current_year.to_s[0..1] + utils.omocodia_decode(raw[:birthdate_year])).to_i
|
73
|
+
val > current_year ? val - 100 : val
|
78
74
|
end
|
79
75
|
|
80
76
|
def month
|
@@ -96,7 +92,7 @@ module ItaxCode
|
|
96
92
|
if place.nil?
|
97
93
|
birthplace(utils.countries, stop: true) unless stop
|
98
94
|
else
|
99
|
-
place.to_h.
|
95
|
+
place.to_h.transform_keys(&:to_sym)
|
100
96
|
end
|
101
97
|
end
|
102
98
|
|
@@ -0,0 +1,211 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ItaxCode
|
4
|
+
# https://github.com/ruby-i18n/i18n/blob/master/lib/i18n/backend/transliterator.rb
|
5
|
+
class Transliterator
|
6
|
+
DEFAULT_REPLACEMENT_CHAR = "?"
|
7
|
+
|
8
|
+
def transliterate(string, replacement = nil)
|
9
|
+
replacement ||= DEFAULT_REPLACEMENT_CHAR
|
10
|
+
string.gsub(/[^\x00-\x7f]/u) { |char| approximations[char] || replacement }
|
11
|
+
end
|
12
|
+
|
13
|
+
private
|
14
|
+
|
15
|
+
def approximations
|
16
|
+
@approximations ||= {
|
17
|
+
"À" => "A",
|
18
|
+
"Á" => "A",
|
19
|
+
"Â" => "A",
|
20
|
+
"Ã" => "A",
|
21
|
+
"Ä" => "A",
|
22
|
+
"Å" => "A",
|
23
|
+
"Æ" => "AE",
|
24
|
+
"Ç" => "C",
|
25
|
+
"È" => "E",
|
26
|
+
"É" => "E",
|
27
|
+
"Ê" => "E",
|
28
|
+
"Ë" => "E",
|
29
|
+
"Ì" => "I",
|
30
|
+
"Í" => "I",
|
31
|
+
"Î" => "I",
|
32
|
+
"Ï" => "I",
|
33
|
+
"Ð" => "D",
|
34
|
+
"Ñ" => "N",
|
35
|
+
"Ò" => "O",
|
36
|
+
"Ó" => "O",
|
37
|
+
"Ô" => "O",
|
38
|
+
"Õ" => "O",
|
39
|
+
"Ö" => "O",
|
40
|
+
"×" => "x",
|
41
|
+
"Ø" => "O",
|
42
|
+
"Ù" => "U",
|
43
|
+
"Ú" => "U",
|
44
|
+
"Û" => "U",
|
45
|
+
"Ü" => "U",
|
46
|
+
"Ý" => "Y",
|
47
|
+
"Þ" => "Th",
|
48
|
+
"ß" => "ss",
|
49
|
+
"ẞ" => "SS",
|
50
|
+
"à" => "a",
|
51
|
+
"á" => "a",
|
52
|
+
"â" => "a",
|
53
|
+
"ã" => "a",
|
54
|
+
"ä" => "a",
|
55
|
+
"å" => "a",
|
56
|
+
"æ" => "ae",
|
57
|
+
"ç" => "c",
|
58
|
+
"è" => "e",
|
59
|
+
"é" => "e",
|
60
|
+
"ê" => "e",
|
61
|
+
"ë" => "e",
|
62
|
+
"ì" => "i",
|
63
|
+
"í" => "i",
|
64
|
+
"î" => "i",
|
65
|
+
"ï" => "i",
|
66
|
+
"ð" => "d",
|
67
|
+
"ñ" => "n",
|
68
|
+
"ò" => "o",
|
69
|
+
"ó" => "o",
|
70
|
+
"ô" => "o",
|
71
|
+
"õ" => "o",
|
72
|
+
"ö" => "o",
|
73
|
+
"ø" => "o",
|
74
|
+
"ù" => "u",
|
75
|
+
"ú" => "u",
|
76
|
+
"û" => "u",
|
77
|
+
"ü" => "u",
|
78
|
+
"ý" => "y",
|
79
|
+
"þ" => "th",
|
80
|
+
"ÿ" => "y",
|
81
|
+
"Ā" => "A",
|
82
|
+
"ā" => "a",
|
83
|
+
"Ă" => "A",
|
84
|
+
"ă" => "a",
|
85
|
+
"Ą" => "A",
|
86
|
+
"ą" => "a",
|
87
|
+
"Ć" => "C",
|
88
|
+
"ć" => "c",
|
89
|
+
"Ĉ" => "C",
|
90
|
+
"ĉ" => "c",
|
91
|
+
"Ċ" => "C",
|
92
|
+
"ċ" => "c",
|
93
|
+
"Č" => "C",
|
94
|
+
"č" => "c",
|
95
|
+
"Ď" => "D",
|
96
|
+
"ď" => "d",
|
97
|
+
"Đ" => "D",
|
98
|
+
"đ" => "d",
|
99
|
+
"Ē" => "E",
|
100
|
+
"ē" => "e",
|
101
|
+
"Ĕ" => "E",
|
102
|
+
"ĕ" => "e",
|
103
|
+
"Ė" => "E",
|
104
|
+
"ė" => "e",
|
105
|
+
"Ę" => "E",
|
106
|
+
"ę" => "e",
|
107
|
+
"Ě" => "E",
|
108
|
+
"ě" => "e",
|
109
|
+
"Ĝ" => "G",
|
110
|
+
"ĝ" => "g",
|
111
|
+
"Ğ" => "G",
|
112
|
+
"ğ" => "g",
|
113
|
+
"Ġ" => "G",
|
114
|
+
"ġ" => "g",
|
115
|
+
"Ģ" => "G",
|
116
|
+
"ģ" => "g",
|
117
|
+
"Ĥ" => "H",
|
118
|
+
"ĥ" => "h",
|
119
|
+
"Ħ" => "H",
|
120
|
+
"ħ" => "h",
|
121
|
+
"Ĩ" => "I",
|
122
|
+
"ĩ" => "i",
|
123
|
+
"Ī" => "I",
|
124
|
+
"ī" => "i",
|
125
|
+
"Ĭ" => "I",
|
126
|
+
"ĭ" => "i",
|
127
|
+
"Į" => "I",
|
128
|
+
"į" => "i",
|
129
|
+
"İ" => "I",
|
130
|
+
"ı" => "i",
|
131
|
+
"IJ" => "IJ",
|
132
|
+
"ij" => "ij",
|
133
|
+
"Ĵ" => "J",
|
134
|
+
"ĵ" => "j",
|
135
|
+
"Ķ" => "K",
|
136
|
+
"ķ" => "k",
|
137
|
+
"ĸ" => "k",
|
138
|
+
"Ĺ" => "L",
|
139
|
+
"ĺ" => "l",
|
140
|
+
"Ļ" => "L",
|
141
|
+
"ļ" => "l",
|
142
|
+
"Ľ" => "L",
|
143
|
+
"ľ" => "l",
|
144
|
+
"Ŀ" => "L",
|
145
|
+
"ŀ" => "l",
|
146
|
+
"Ł" => "L",
|
147
|
+
"ł" => "l",
|
148
|
+
"Ń" => "N",
|
149
|
+
"ń" => "n",
|
150
|
+
"Ņ" => "N",
|
151
|
+
"ņ" => "n",
|
152
|
+
"Ň" => "N",
|
153
|
+
"ň" => "n",
|
154
|
+
"ʼn" => "'n",
|
155
|
+
"Ŋ" => "NG",
|
156
|
+
"ŋ" => "ng",
|
157
|
+
"Ō" => "O",
|
158
|
+
"ō" => "o",
|
159
|
+
"Ŏ" => "O",
|
160
|
+
"ŏ" => "o",
|
161
|
+
"Ő" => "O",
|
162
|
+
"ő" => "o",
|
163
|
+
"Œ" => "OE",
|
164
|
+
"œ" => "oe",
|
165
|
+
"Ŕ" => "R",
|
166
|
+
"ŕ" => "r",
|
167
|
+
"Ŗ" => "R",
|
168
|
+
"ŗ" => "r",
|
169
|
+
"Ř" => "R",
|
170
|
+
"ř" => "r",
|
171
|
+
"Ś" => "S",
|
172
|
+
"ś" => "s",
|
173
|
+
"Ŝ" => "S",
|
174
|
+
"ŝ" => "s",
|
175
|
+
"Ş" => "S",
|
176
|
+
"ş" => "s",
|
177
|
+
"Š" => "S",
|
178
|
+
"š" => "s",
|
179
|
+
"Ţ" => "T",
|
180
|
+
"ţ" => "t",
|
181
|
+
"Ť" => "T",
|
182
|
+
"ť" => "t",
|
183
|
+
"Ŧ" => "T",
|
184
|
+
"ŧ" => "t",
|
185
|
+
"Ũ" => "U",
|
186
|
+
"ũ" => "u",
|
187
|
+
"Ū" => "U",
|
188
|
+
"ū" => "u",
|
189
|
+
"Ŭ" => "U",
|
190
|
+
"ŭ" => "u",
|
191
|
+
"Ů" => "U",
|
192
|
+
"ů" => "u",
|
193
|
+
"Ű" => "U",
|
194
|
+
"ű" => "u",
|
195
|
+
"Ų" => "U",
|
196
|
+
"ų" => "u",
|
197
|
+
"Ŵ" => "W",
|
198
|
+
"ŵ" => "w",
|
199
|
+
"Ŷ" => "Y",
|
200
|
+
"ŷ" => "y",
|
201
|
+
"Ÿ" => "Y",
|
202
|
+
"Ź" => "Z",
|
203
|
+
"ź" => "z",
|
204
|
+
"Ż" => "Z",
|
205
|
+
"ż" => "z",
|
206
|
+
"Ž" => "Z",
|
207
|
+
"ž" => "z"
|
208
|
+
}
|
209
|
+
end
|
210
|
+
end
|
211
|
+
end
|
data/lib/itax_code/utils.rb
CHANGED
@@ -1,20 +1,37 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require "csv"
|
4
|
+
require "itax_code/transliterator"
|
4
5
|
|
5
6
|
module ItaxCode
|
6
7
|
class Utils
|
7
|
-
def
|
8
|
+
def blank?(obj)
|
9
|
+
obj.respond_to?(:empty?) ? !!obj.empty? : !obj
|
10
|
+
end
|
11
|
+
|
12
|
+
def present?(obj)
|
13
|
+
!blank?(obj)
|
14
|
+
end
|
15
|
+
|
16
|
+
def slugged(string)
|
17
|
+
transliterated = transliterate(string.downcase.strip)
|
18
|
+
transliterated.gsub(/[^\w-]+/, "-").gsub(/-{2,}/, "-").gsub(/^-+|-+$/, "")
|
19
|
+
end
|
20
|
+
|
21
|
+
def transliterate(string)
|
22
|
+
return string if string.ascii_only?
|
23
|
+
|
24
|
+
transliterator = Transliterator.new
|
25
|
+
transliterator.transliterate(string.unicode_normalize(:nfc))
|
26
|
+
end
|
27
|
+
|
28
|
+
def tax_code_sections_regex
|
8
29
|
/^([A-Z]{3})([A-Z]{3})
|
9
30
|
(([A-Z\d]{2})([ABCDEHLMPRST]{1})([A-Z\d]{2}))
|
10
31
|
([A-Z]{1}[A-Z\d]{3})
|
11
32
|
([A-Z]{1})$/x
|
12
33
|
end
|
13
34
|
|
14
|
-
def slugged(str, separator = "-")
|
15
|
-
str.gsub(/\s*@\s*/, " at ").gsub(/\s*&\s*/, " and ").parameterize(separator: separator)
|
16
|
-
end
|
17
|
-
|
18
35
|
def months
|
19
36
|
%w[A B C D E H L M P R S T]
|
20
37
|
end
|
data/lib/itax_code/version.rb
CHANGED
data/lib/itax_code.rb
CHANGED
@@ -1,15 +1,12 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require "active_support/all"
|
4
|
-
|
5
3
|
require "itax_code/version"
|
6
4
|
require "itax_code/utils"
|
7
5
|
require "itax_code/encoder"
|
8
6
|
require "itax_code/parser"
|
7
|
+
require "itax_code/error"
|
9
8
|
|
10
9
|
module ItaxCode
|
11
|
-
Error = Class.new(StandardError)
|
12
|
-
|
13
10
|
class << self
|
14
11
|
# Encodes the user tax code.
|
15
12
|
#
|
data/rakelib/cities.rake
CHANGED
@@ -16,7 +16,7 @@ namespace :cities do
|
|
16
16
|
output_string = CSV.generate do |csv|
|
17
17
|
csv << %w[code province name created_on deleted_on]
|
18
18
|
|
19
|
-
CSV.foreach(tempfile.path, headers: true) do |row|
|
19
|
+
CSV.foreach(tempfile.path, encoding: "bom|utf-8", headers: true) do |row|
|
20
20
|
csv << [
|
21
21
|
row["CODCATASTALE"],
|
22
22
|
row["SIGLAPROVINCIA"],
|
metadata
CHANGED
@@ -1,29 +1,15 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: itax_code
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.0.
|
4
|
+
version: 2.0.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Matteo Rossi
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2023-
|
12
|
-
dependencies:
|
13
|
-
- !ruby/object:Gem::Dependency
|
14
|
-
name: activesupport
|
15
|
-
requirement: !ruby/object:Gem::Requirement
|
16
|
-
requirements:
|
17
|
-
- - ">="
|
18
|
-
- !ruby/object:Gem::Version
|
19
|
-
version: '0'
|
20
|
-
type: :runtime
|
21
|
-
prerelease: false
|
22
|
-
version_requirements: !ruby/object:Gem::Requirement
|
23
|
-
requirements:
|
24
|
-
- - ">="
|
25
|
-
- !ruby/object:Gem::Version
|
26
|
-
version: '0'
|
11
|
+
date: 2023-11-04 00:00:00.000000000 Z
|
12
|
+
dependencies: []
|
27
13
|
description:
|
28
14
|
email:
|
29
15
|
- mttrss5@gmail.com
|
@@ -37,7 +23,6 @@ files:
|
|
37
23
|
- ".github/workflows/test.yml"
|
38
24
|
- ".gitignore"
|
39
25
|
- ".rubocop.yml"
|
40
|
-
- ".travis.yml"
|
41
26
|
- CHANGELOG.md
|
42
27
|
- CODE_OF_CONDUCT.md
|
43
28
|
- Gemfile
|
@@ -51,8 +36,10 @@ files:
|
|
51
36
|
- lib/itax_code/data/cities.csv
|
52
37
|
- lib/itax_code/data/countries.csv
|
53
38
|
- lib/itax_code/encoder.rb
|
39
|
+
- lib/itax_code/error.rb
|
54
40
|
- lib/itax_code/omocode.rb
|
55
41
|
- lib/itax_code/parser.rb
|
42
|
+
- lib/itax_code/transliterator.rb
|
56
43
|
- lib/itax_code/utils.rb
|
57
44
|
- lib/itax_code/version.rb
|
58
45
|
- rakelib/cities.rake
|