itax_code 0.1.4 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -10,9 +10,9 @@ module ItaxCode
10
10
  # @example
11
11
  # ItaxCode::Encoder.new(
12
12
  # surname: "Rossi",
13
- # name: "Matteo",
13
+ # name: "Mario",
14
14
  # gender: "M",
15
- # birthdate: "1990-08-23",
15
+ # birthdate: "1980-01-01",
16
16
  # birthplace: "Milano"
17
17
  # ).encode
18
18
  #
@@ -24,15 +24,12 @@ module ItaxCode
24
24
  @surname = data[:surname]
25
25
  @name = data[:name]
26
26
  @gender = data[:gender]&.upcase
27
- @birthdate = Date.parse(data[:birthdate].to_s)
27
+ @birthdate = data[:birthdate].to_s
28
28
  @birthplace = data[:birthplace]
29
29
  @utils = utils
30
+ validate_data_presence!
30
31
 
31
- instance_variables.each do |ivar|
32
- next if instance_variable_get(ivar).present?
33
-
34
- raise MissingDataError, "missing #{ivar} value"
35
- end
32
+ @birthdate = parse_birthdate!
36
33
  end
37
34
 
38
35
  # Computes the tax code from its components.
@@ -64,8 +61,7 @@ module ItaxCode
64
61
  vowels = utils.extract_vowels chars
65
62
 
66
63
  if consonants.length > 3
67
- consonants =
68
- consonants.chars.values_at(0, 2..consonants.chars.size).join
64
+ consonants = consonants.chars.values_at(0, 2..consonants.chars.size).join
69
65
  end
70
66
 
71
67
  "#{consonants[0..2]}#{vowels[0..2]}XXX"[0..2].upcase
@@ -78,15 +74,30 @@ module ItaxCode
78
74
  "#{year}#{month}#{day}"
79
75
  end
80
76
 
81
- def encode_birthplace(src = utils.cities, exit: false)
82
- place = src.find do |item|
83
- utils.slugged(birthplace) == utils.slugged(item["name"])
84
- end
77
+ def encode_birthplace(src = utils.cities, stop: false)
78
+ lookup_key = birthplace.match?(/^\w{1}\d{3}$/) ? "code" : "name"
79
+ place_slug = utils.slugged(birthplace)
80
+ place_item = src.find { |i| place_slug == utils.slugged(i[lookup_key]) }
85
81
 
86
- code = place.try(:[], "code")
82
+ code = place_item.try(:[], "code")
87
83
  return code if code.present?
84
+ raise MissingDataError, "no code found for #{birthplace}" if stop
85
+
86
+ encode_birthplace(utils.countries, stop: true)
87
+ end
88
+
89
+ def validate_data_presence!
90
+ instance_variables.each do |ivar|
91
+ next if instance_variable_get(ivar).present?
92
+
93
+ raise MissingDataError, "missing #{ivar} value"
94
+ end
95
+ end
88
96
 
89
- exit || encode_birthplace(utils.countries, exit: true)
97
+ def parse_birthdate!
98
+ Date.parse(birthdate)
99
+ rescue StandardError
100
+ raise ArgumentError, "#{birthdate} is not a valid date"
90
101
  end
91
102
  end
92
103
  end
@@ -25,15 +25,10 @@ module ItaxCode
25
25
  #
26
26
  # @return [Hash]
27
27
  def decode
28
- year = decode_year
29
- month = utils.months.find_index(raw[:birthdate_month]) + 1
30
- day, gender = decode_day_and_gender
31
- birthplace = decode_birthplace
32
-
33
28
  {
34
29
  code: tax_code,
35
30
  gender: gender,
36
- birthdate: [year, month, day].join("-"),
31
+ birthdate: birthdate,
37
32
  birthplace: birthplace,
38
33
  omocodes: Omocode.new(tax_code).list,
39
34
  raw: raw
@@ -45,53 +40,66 @@ module ItaxCode
45
40
  attr_accessor :tax_code, :utils
46
41
 
47
42
  def raw
48
- matches = tax_code.scan(utils.regex).flatten
49
-
50
- {
51
- surname: matches[0],
52
- name: matches[1],
53
- birthdate: matches[2],
54
- birthdate_year: matches[3],
55
- birthdate_month: matches[4],
56
- birthdate_day: matches[5],
57
- birthplace: matches[6],
58
- cin: matches[7]
43
+ @raw ||= {
44
+ surname: raw_matches[0],
45
+ name: raw_matches[1],
46
+ birthdate: raw_matches[2],
47
+ birthdate_year: raw_matches[3],
48
+ birthdate_month: raw_matches[4],
49
+ birthdate_day: raw_matches[5],
50
+ birthplace: raw_matches[6],
51
+ cin: raw_matches[7]
59
52
  }
60
53
  end
61
54
 
62
- def decode_year
63
- year = utils.omocodia_decode raw[:birthdate_year]
64
- year = (Date.today.year.to_s[0..1] + year).to_i
65
- year -= 100 if year > Date.today.year
66
- year
55
+ def raw_matches
56
+ @raw_matches ||= tax_code.scan(utils.regex).flatten
67
57
  end
68
58
 
69
- def decode_day_and_gender
70
- day = utils.omocodia_decode(raw[:birthdate_day]).to_i
59
+ def gender
60
+ val = utils.omocodia_decode(raw[:birthdate_day]).to_i
61
+ val > 40 ? "F" : "M"
62
+ end
71
63
 
72
- if day > 40
73
- day -= 40
74
- [day, "F"]
75
- else
76
- [day, "M"]
77
- end
64
+ # This method tries to calculate the year based on a raw data. This means that the returned
65
+ # value could be wrong. E.g. a person born on 1920 would have birthdate_year = 20 meaning
66
+ # that both 1920 and 2020 could be valid born years.
67
+ def year
68
+ val = (Date.today.year.to_s[0..1] + utils.omocodia_decode(raw[:birthdate_year])).to_i
69
+ val > Date.today.year ? val - 100 : val
78
70
  end
79
71
 
80
- def decode_birthplace(src = utils.cities, exit: false)
81
- place = src.find do |item|
82
- item["code"] == city_code && !item["name"].include?("soppresso")
83
- end
72
+ def month
73
+ utils.months.find_index(raw[:birthdate_month]) + 1
74
+ end
75
+
76
+ def day
77
+ val = utils.omocodia_decode(raw[:birthdate_day]).to_i
78
+ val > 40 ? val - 40 : val
79
+ end
80
+
81
+ def birthdate
82
+ @birthdate ||= Date.parse("#{year}-#{month}-#{day}").to_s
83
+ end
84
+
85
+ def birthplace(src = utils.cities, stop: false)
86
+ place = src.find { |item| item["code"] == birthplace_code && in_dates?(item) }
84
87
 
85
88
  if place.nil?
86
- exit ? return : decode_birthplace(utils.countries, exit: true)
89
+ birthplace(utils.countries, stop: true) unless stop
87
90
  else
88
- place["name"] = place["name"].gsub(" (soppresso)", "")
89
91
  place.to_h.deep_symbolize_keys
90
92
  end
91
93
  end
92
94
 
93
- def city_code
95
+ def birthplace_code
94
96
  raw[:birthplace][0] + utils.omocodia_decode(raw[:birthplace][1..-1])
95
97
  end
98
+
99
+ def in_dates?(item)
100
+ created_on = Date.parse item.fetch("created_on", "0000-01-01")
101
+ deleted_on = Date.parse item.fetch("deleted_on", "9999-12-31")
102
+ Date.parse(birthdate).between? created_on, deleted_on
103
+ end
96
104
  end
97
105
  end
@@ -92,8 +92,7 @@ module ItaxCode
92
92
  tot = 0
93
93
 
94
94
  code.chars.each_with_index do |char, index|
95
- tot += cin_odds[char.to_sym] if (index + 1).odd?
96
- tot += cin_evens[char.to_sym] if (index + 1).even?
95
+ tot += (index + 1).odd? ? cin_odds[char.to_sym] : cin_evens[char.to_sym]
97
96
  end
98
97
 
99
98
  cin_remainders[tot % 26]
@@ -1,3 +1,3 @@
1
1
  module ItaxCode
2
- VERSION = "0.1.4".freeze
2
+ VERSION = "0.3.0".freeze
3
3
  end
@@ -0,0 +1,35 @@
1
+ require "csv"
2
+ require "net/http"
3
+ require "tempfile"
4
+ require "uri"
5
+
6
+ namespace :cities do
7
+ desc "Import cities from Istat remote CSV"
8
+ task :import do
9
+ tempfile = Tempfile.new
10
+ tempfile.write Net::HTTP.get(
11
+ URI("https://raw.githubusercontent.com/italia/anpr/master/src/archivi/ANPR_archivio_comuni.csv")
12
+ )
13
+
14
+ output_string = CSV.generate do |csv|
15
+ csv << %w[code province name created_on deleted_on]
16
+
17
+ CSV.foreach(tempfile.path, headers: true) do |row|
18
+ csv << [
19
+ row["CODCATASTALE"],
20
+ row["SIGLAPROVINCIA"],
21
+ row["DENOMINAZIONE_IT"].upcase,
22
+ row["DATAISTITUZIONE"],
23
+ row["DATACESSAZIONE"]
24
+ ]
25
+ end
26
+ end
27
+
28
+ File.open("lib/itax_code/data/cities.csv", "w") do |output_file|
29
+ output_file.write(output_string)
30
+ end
31
+ ensure
32
+ tempfile.close
33
+ tempfile.unlink
34
+ end
35
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: itax_code
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.4
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Matteo Rossi
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2021-11-03 00:00:00.000000000 Z
11
+ date: 2023-06-30 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -24,118 +24,6 @@ dependencies:
24
24
  - - ">="
25
25
  - !ruby/object:Gem::Version
26
26
  version: '0'
27
- - !ruby/object:Gem::Dependency
28
- name: byebug
29
- requirement: !ruby/object:Gem::Requirement
30
- requirements:
31
- - - ">="
32
- - !ruby/object:Gem::Version
33
- version: '0'
34
- type: :development
35
- prerelease: false
36
- version_requirements: !ruby/object:Gem::Requirement
37
- requirements:
38
- - - ">="
39
- - !ruby/object:Gem::Version
40
- version: '0'
41
- - !ruby/object:Gem::Dependency
42
- name: minitest
43
- requirement: !ruby/object:Gem::Requirement
44
- requirements:
45
- - - ">="
46
- - !ruby/object:Gem::Version
47
- version: '0'
48
- type: :development
49
- prerelease: false
50
- version_requirements: !ruby/object:Gem::Requirement
51
- requirements:
52
- - - ">="
53
- - !ruby/object:Gem::Version
54
- version: '0'
55
- - !ruby/object:Gem::Dependency
56
- name: mocha
57
- requirement: !ruby/object:Gem::Requirement
58
- requirements:
59
- - - ">="
60
- - !ruby/object:Gem::Version
61
- version: '0'
62
- type: :development
63
- prerelease: false
64
- version_requirements: !ruby/object:Gem::Requirement
65
- requirements:
66
- - - ">="
67
- - !ruby/object:Gem::Version
68
- version: '0'
69
- - !ruby/object:Gem::Dependency
70
- name: rake
71
- requirement: !ruby/object:Gem::Requirement
72
- requirements:
73
- - - ">="
74
- - !ruby/object:Gem::Version
75
- version: '0'
76
- type: :development
77
- prerelease: false
78
- version_requirements: !ruby/object:Gem::Requirement
79
- requirements:
80
- - - ">="
81
- - !ruby/object:Gem::Version
82
- version: '0'
83
- - !ruby/object:Gem::Dependency
84
- name: rubocop
85
- requirement: !ruby/object:Gem::Requirement
86
- requirements:
87
- - - ">="
88
- - !ruby/object:Gem::Version
89
- version: '0'
90
- type: :development
91
- prerelease: false
92
- version_requirements: !ruby/object:Gem::Requirement
93
- requirements:
94
- - - ">="
95
- - !ruby/object:Gem::Version
96
- version: '0'
97
- - !ruby/object:Gem::Dependency
98
- name: rubocop-minitest
99
- requirement: !ruby/object:Gem::Requirement
100
- requirements:
101
- - - ">="
102
- - !ruby/object:Gem::Version
103
- version: '0'
104
- type: :development
105
- prerelease: false
106
- version_requirements: !ruby/object:Gem::Requirement
107
- requirements:
108
- - - ">="
109
- - !ruby/object:Gem::Version
110
- version: '0'
111
- - !ruby/object:Gem::Dependency
112
- name: rubocop-performance
113
- requirement: !ruby/object:Gem::Requirement
114
- requirements:
115
- - - ">="
116
- - !ruby/object:Gem::Version
117
- version: '0'
118
- type: :development
119
- prerelease: false
120
- version_requirements: !ruby/object:Gem::Requirement
121
- requirements:
122
- - - ">="
123
- - !ruby/object:Gem::Version
124
- version: '0'
125
- - !ruby/object:Gem::Dependency
126
- name: simplecov
127
- requirement: !ruby/object:Gem::Requirement
128
- requirements:
129
- - - ">="
130
- - !ruby/object:Gem::Version
131
- version: '0'
132
- type: :development
133
- prerelease: false
134
- version_requirements: !ruby/object:Gem::Requirement
135
- requirements:
136
- - - ">="
137
- - !ruby/object:Gem::Version
138
- version: '0'
139
27
  description:
140
28
  email:
141
29
  - mttrss5@gmail.com
@@ -144,15 +32,15 @@ extensions: []
144
32
  extra_rdoc_files: []
145
33
  files:
146
34
  - ".github/CODEOWNERS"
147
- - ".github/workflows/build-and-push.yml"
148
35
  - ".github/workflows/lint.yml"
36
+ - ".github/workflows/release.yml"
149
37
  - ".github/workflows/test.yml"
150
38
  - ".gitignore"
151
39
  - ".rubocop.yml"
152
40
  - ".travis.yml"
41
+ - CHANGELOG.md
153
42
  - CODE_OF_CONDUCT.md
154
43
  - Gemfile
155
- - Gemfile.lock
156
44
  - README.md
157
45
  - Rakefile
158
46
  - bin/console
@@ -168,6 +56,7 @@ files:
168
56
  - lib/itax_code/utils.rb
169
57
  - lib/itax_code/validator.rb
170
58
  - lib/itax_code/version.rb
59
+ - rakelib/cities.rake
171
60
  homepage: https://github.com/matteoredz/itax-code
172
61
  licenses:
173
62
  - MIT
@@ -1,27 +0,0 @@
1
- ---
2
- name: Build and Push
3
-
4
- on:
5
- push:
6
- branches:
7
- - main
8
-
9
- jobs:
10
- build:
11
- runs-on: ubuntu-latest
12
- steps:
13
- - name: Checkout
14
- uses: actions/checkout@v2
15
- - uses: fregante/setup-git-user@v1
16
- - name: Set up Ruby
17
- uses: ruby/setup-ruby@v1
18
- with:
19
- bundler-cache: true
20
- ruby-version: 2.7.0
21
- - run: bundle install
22
- - name: Build and Push to RubyGems
23
- run: ./bin/release
24
- env:
25
- GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}}
26
- RUBYGEMS_API_KEY: ${{secrets.RUBYGEMS_API_KEY}}
27
- ...
data/Gemfile.lock DELETED
@@ -1,74 +0,0 @@
1
- PATH
2
- remote: .
3
- specs:
4
- itax_code (0.1.4)
5
- activesupport
6
-
7
- GEM
8
- remote: https://rubygems.org/
9
- specs:
10
- activesupport (6.1.4.1)
11
- concurrent-ruby (~> 1.0, >= 1.0.2)
12
- i18n (>= 1.6, < 2)
13
- minitest (>= 5.1)
14
- tzinfo (~> 2.0)
15
- zeitwerk (~> 2.3)
16
- ast (2.4.2)
17
- byebug (11.1.3)
18
- concurrent-ruby (1.1.9)
19
- docile (1.4.0)
20
- i18n (1.8.11)
21
- concurrent-ruby (~> 1.0)
22
- minitest (5.14.4)
23
- mocha (1.13.0)
24
- parallel (1.21.0)
25
- parser (3.0.2.0)
26
- ast (~> 2.4.1)
27
- rainbow (3.0.0)
28
- rake (13.0.6)
29
- regexp_parser (2.1.1)
30
- rexml (3.2.5)
31
- rubocop (1.22.3)
32
- parallel (~> 1.10)
33
- parser (>= 3.0.0.0)
34
- rainbow (>= 2.2.2, < 4.0)
35
- regexp_parser (>= 1.8, < 3.0)
36
- rexml
37
- rubocop-ast (>= 1.12.0, < 2.0)
38
- ruby-progressbar (~> 1.7)
39
- unicode-display_width (>= 1.4.0, < 3.0)
40
- rubocop-ast (1.12.0)
41
- parser (>= 3.0.1.1)
42
- rubocop-minitest (0.15.2)
43
- rubocop (>= 0.90, < 2.0)
44
- rubocop-performance (1.12.0)
45
- rubocop (>= 1.7.0, < 2.0)
46
- rubocop-ast (>= 0.4.0)
47
- ruby-progressbar (1.11.0)
48
- simplecov (0.21.2)
49
- docile (~> 1.1)
50
- simplecov-html (~> 0.11)
51
- simplecov_json_formatter (~> 0.1)
52
- simplecov-html (0.12.3)
53
- simplecov_json_formatter (0.1.3)
54
- tzinfo (2.0.4)
55
- concurrent-ruby (~> 1.0)
56
- unicode-display_width (2.1.0)
57
- zeitwerk (2.5.1)
58
-
59
- PLATFORMS
60
- ruby
61
-
62
- DEPENDENCIES
63
- byebug
64
- itax_code!
65
- minitest
66
- mocha
67
- rake
68
- rubocop
69
- rubocop-minitest
70
- rubocop-performance
71
- simplecov
72
-
73
- BUNDLED WITH
74
- 2.1.4