itax_code 0.4.0 → 1.0.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: ef915bc679fc9d2e15a5935b64e4c31cab6b638d0dc077d25f1f3ba7ab2859ef
4
- data.tar.gz: 5c4ad64f192cae5530e5a434984539b9f5c0e27ad771d4bbd461118151ba5472
3
+ metadata.gz: a38d68de9f4fc5be15da055a5166c402adbe71d67b9e73213875e28c83b17db6
4
+ data.tar.gz: 7e27421ed321f9f6a8b8d0ec2ba38d005a81414401d5fbfbaa434c6a17e8d40d
5
5
  SHA512:
6
- metadata.gz: 0f80f432773b74fe19d74312c249279204681f211ab73bdaf60bde1c4a4fac1eace749a2bfaae75a38cf692e08b42f88723d27de9e9b29da81580980e9a79039
7
- data.tar.gz: c0758b8d0fc862dd67e5a50842c17723368cbcc7a9e987c3e9d2683e992f55fb346cc6bc2e87374069304f247d1d0e24917c5eb0eee8b9d67b665444f79c0984
6
+ metadata.gz: 724473a7faa374ac886a4a65cf37fe0168e4f1de0e318be0155f42b525d4ee74252c60a474e5db794c2879792f82f9c912ea2d7385b3a5724ac4d042e08d5362
7
+ data.tar.gz: 7af13a9eb19e9e3558bf83072448d561b86e964a61e3c4444638b6c7ceb938a4c84232b95ec74386f10358c8f205cd4a99b54bc9e6f14152b72d87ace7635bfa
data/.rubocop.yml CHANGED
@@ -11,6 +11,9 @@ AllCops:
11
11
  Bundler/OrderedGems:
12
12
  Enabled: false
13
13
 
14
+ Gemspec/RequireMFA:
15
+ Enabled: false
16
+
14
17
  Layout/EmptyLineBetweenDefs:
15
18
  Enabled: true
16
19
  AllowAdjacentOneLineDefs: true
@@ -34,6 +37,7 @@ Metrics/BlockLength:
34
37
  Metrics/ClassLength:
35
38
  Enabled: true
36
39
  Exclude:
40
+ - 'lib/itax_code/utils.rb'
37
41
  - 'test/**/*'
38
42
 
39
43
  Metrics/MethodLength:
data/CHANGELOG.md CHANGED
@@ -1,5 +1,30 @@
1
1
  # Changelog
2
2
 
3
+ ## [1.0.0](https://github.com/matteoredz/itax-code/compare/v0.4.1...v1.0.0) (2023-08-30)
4
+
5
+
6
+ ### ⚠ BREAKING CHANGES
7
+
8
+ * allow empty or partial data argument in ItaxCode.valid? ([#26](https://github.com/matteoredz/itax-code/issues/26))
9
+ * raise InvalidControlInternalNumberError on cin mismatch ([#25](https://github.com/matteoredz/itax-code/issues/25))
10
+
11
+ ### Features
12
+
13
+ * allow empty or partial data argument in ItaxCode.valid? ([#26](https://github.com/matteoredz/itax-code/issues/26)) ([d02da6d](https://github.com/matteoredz/itax-code/commit/d02da6d17a4c04e1a5e07d7dd9d9d966479346bd))
14
+
15
+
16
+ ### Bug Fixes
17
+
18
+ * compute omocodes from the original one ([#22](https://github.com/matteoredz/itax-code/issues/22)) ([b8a963f](https://github.com/matteoredz/itax-code/commit/b8a963faba2c46e1d23c0dc643a257aabd648dd9))
19
+ * raise InvalidControlInternalNumberError on cin mismatch ([#25](https://github.com/matteoredz/itax-code/issues/25)) ([121cbca](https://github.com/matteoredz/itax-code/commit/121cbcaf75788c99bee4ffd7a997d07783a7fc15))
20
+
21
+ ## [0.4.1](https://github.com/matteoredz/itax-code/compare/v0.4.0...v0.4.1) (2023-08-08)
22
+
23
+
24
+ ### Bug Fixes
25
+
26
+ * disable MFA as it breaks the CI ([#20](https://github.com/matteoredz/itax-code/issues/20)) ([7c9568e](https://github.com/matteoredz/itax-code/commit/7c9568e66618e324d4da137ddc6d0680b6900daa))
27
+
3
28
  ## [0.4.0](https://github.com/matteoredz/itax-code/compare/v0.3.0...v0.4.0) (2023-08-08)
4
29
 
5
30
 
data/README.md CHANGED
@@ -54,11 +54,131 @@ ItaxCode.decode("RSSMRA80A01F205X")
54
54
  # omocodes: %w[
55
55
  # RSSMRA80A01F205X
56
56
  # RSSMRA80A01F20RS
57
+ # RSSMRA80A01F2L5I
58
+ # RSSMRA80A01FN05M
59
+ # RSSMRA80A0MF205P
60
+ # RSSMRA80AL1F205I
61
+ # RSSMRA8LA01F205I
62
+ # RSSMRAU0A01F205U
57
63
  # RSSMRA80A01F2LRD
64
+ # RSSMRA80A01FN0RH
65
+ # RSSMRA80A0MF20RK
66
+ # RSSMRA80AL1F20RD
67
+ # RSSMRA8LA01F20RD
68
+ # RSSMRAU0A01F20RP
69
+ # RSSMRA80A01FNL5X
70
+ # RSSMRA80A0MF2L5A
71
+ # RSSMRA80AL1F2L5T
72
+ # RSSMRA8LA01F2L5T
73
+ # RSSMRAU0A01F2L5F
74
+ # RSSMRA80A0MFN05E
75
+ # RSSMRA80AL1FN05X
76
+ # RSSMRA8LA01FN05X
77
+ # RSSMRAU0A01FN05J
78
+ # RSSMRA80ALMF205A
79
+ # RSSMRA8LA0MF205A
80
+ # RSSMRAU0A0MF205M
81
+ # RSSMRA8LAL1F205T
82
+ # RSSMRAU0AL1F205F
83
+ # RSSMRAULA01F205F
58
84
  # RSSMRA80A01FNLRS
85
+ # RSSMRA80A0MF2LRV
86
+ # RSSMRA80AL1F2LRO
87
+ # RSSMRA8LA01F2LRO
88
+ # RSSMRAU0A01F2LRA
89
+ # RSSMRA80A0MFN0RZ
90
+ # RSSMRA80AL1FN0RS
91
+ # RSSMRA8LA01FN0RS
92
+ # RSSMRAU0A01FN0RE
93
+ # RSSMRA80ALMF20RV
94
+ # RSSMRA8LA0MF20RV
95
+ # RSSMRAU0A0MF20RH
96
+ # RSSMRA8LAL1F20RO
97
+ # RSSMRAU0AL1F20RA
98
+ # RSSMRAULA01F20RA
99
+ # RSSMRA80A0MFNL5P
100
+ # RSSMRA80AL1FNL5I
101
+ # RSSMRA8LA01FNL5I
102
+ # RSSMRAU0A01FNL5U
103
+ # RSSMRA80ALMF2L5L
104
+ # RSSMRA8LA0MF2L5L
105
+ # RSSMRAU0A0MF2L5X
106
+ # RSSMRA8LAL1F2L5E
107
+ # RSSMRAU0AL1F2L5Q
108
+ # RSSMRAULA01F2L5Q
109
+ # RSSMRA80ALMFN05P
110
+ # RSSMRA8LA0MFN05P
111
+ # RSSMRAU0A0MFN05B
112
+ # RSSMRA8LAL1FN05I
113
+ # RSSMRAU0AL1FN05U
114
+ # RSSMRAULA01FN05U
115
+ # RSSMRA8LALMF205L
116
+ # RSSMRAU0ALMF205X
117
+ # RSSMRAULA0MF205X
118
+ # RSSMRAULAL1F205Q
59
119
  # RSSMRA80A0MFNLRK
120
+ # RSSMRA80AL1FNLRD
121
+ # RSSMRA8LA01FNLRD
122
+ # RSSMRAU0A01FNLRP
123
+ # RSSMRA80ALMF2LRG
124
+ # RSSMRA8LA0MF2LRG
125
+ # RSSMRAU0A0MF2LRS
126
+ # RSSMRA8LAL1F2LRZ
127
+ # RSSMRAU0AL1F2LRL
128
+ # RSSMRAULA01F2LRL
129
+ # RSSMRA80ALMFN0RK
130
+ # RSSMRA8LA0MFN0RK
131
+ # RSSMRAU0A0MFN0RW
132
+ # RSSMRA8LAL1FN0RD
133
+ # RSSMRAU0AL1FN0RP
134
+ # RSSMRAULA01FN0RP
135
+ # RSSMRA8LALMF20RG
136
+ # RSSMRAU0ALMF20RS
137
+ # RSSMRAULA0MF20RS
138
+ # RSSMRAULAL1F20RL
139
+ # RSSMRA80ALMFNL5A
140
+ # RSSMRA8LA0MFNL5A
141
+ # RSSMRAU0A0MFNL5M
142
+ # RSSMRA8LAL1FNL5T
143
+ # RSSMRAU0AL1FNL5F
144
+ # RSSMRAULA01FNL5F
145
+ # RSSMRA8LALMF2L5W
146
+ # RSSMRAU0ALMF2L5I
147
+ # RSSMRAULA0MF2L5I
148
+ # RSSMRAULAL1F2L5B
149
+ # RSSMRA8LALMFN05A
150
+ # RSSMRAU0ALMFN05M
151
+ # RSSMRAULA0MFN05M
152
+ # RSSMRAULAL1FN05F
153
+ # RSSMRAULALMF205I
60
154
  # RSSMRA80ALMFNLRV
155
+ # RSSMRA8LA0MFNLRV
156
+ # RSSMRAU0A0MFNLRH
157
+ # RSSMRA8LAL1FNLRO
158
+ # RSSMRAU0AL1FNLRA
159
+ # RSSMRAULA01FNLRA
160
+ # RSSMRA8LALMF2LRR
161
+ # RSSMRAU0ALMF2LRD
162
+ # RSSMRAULA0MF2LRD
163
+ # RSSMRAULAL1F2LRW
164
+ # RSSMRA8LALMFN0RV
165
+ # RSSMRAU0ALMFN0RH
166
+ # RSSMRAULA0MFN0RH
167
+ # RSSMRAULAL1FN0RA
168
+ # RSSMRAULALMF20RD
169
+ # RSSMRA8LALMFNL5L
170
+ # RSSMRAU0ALMFNL5X
171
+ # RSSMRAULA0MFNL5X
172
+ # RSSMRAULAL1FNL5Q
173
+ # RSSMRAULALMF2L5T
174
+ # RSSMRAULALMFN05X
61
175
  # RSSMRA8LALMFNLRG
176
+ # RSSMRAU0ALMFNLRS
177
+ # RSSMRAULA0MFNLRS
178
+ # RSSMRAULAL1FNLRL
179
+ # RSSMRAULALMF2LRO
180
+ # RSSMRAULALMFN0RS
181
+ # RSSMRAULALMFNL5I
62
182
  # RSSMRAULALMFNLRD
63
183
  # ],
64
184
  # raw: {
data/itax_code.gemspec CHANGED
@@ -25,5 +25,5 @@ Gem::Specification.new do |spec|
25
25
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
26
26
  spec.require_paths = ["lib"]
27
27
  spec.add_dependency "activesupport"
28
- spec.metadata["rubygems_mfa_required"] = "true"
28
+ spec.metadata["rubygems_mfa_required"] = "false"
29
29
  end
@@ -20,7 +20,7 @@ module ItaxCode
20
20
  #
21
21
  # @return [String] The encoded tax code
22
22
  class Encoder
23
- class MissingDataError < StandardError; end
23
+ MissingDataError = Class.new(StandardError)
24
24
 
25
25
  def initialize(data = {}, utils = Utils.new)
26
26
  @surname = data[:surname]
@@ -19,7 +19,7 @@ module ItaxCode
19
19
  # @return [Array]
20
20
  def omocodes
21
21
  [original_omocode] + utils.omocodia_indexes_combos.map do |combo|
22
- omocode(combo, ->(char) { utils.omocodia_encode(char) })
22
+ omocode(original_omocode, combo, ->(char) { utils.omocodia_encode(char) })
23
23
  end
24
24
  end
25
25
 
@@ -28,13 +28,15 @@ module ItaxCode
28
28
  #
29
29
  # @return [String]
30
30
  def original_omocode
31
- omocode(utils.omocodia_indexes, ->(char) { utils.omocodia_decode(char) })
31
+ @original_omocode ||= omocode(
32
+ tax_code, utils.omocodia_indexes, ->(char) { utils.omocodia_decode(char) }
33
+ )
32
34
  end
33
35
 
34
36
  private
35
37
 
36
- def omocode(indexes, translation)
37
- chars = tax_code[0..14].chars
38
+ def omocode(code, indexes, translation)
39
+ chars = code[0..14].chars
38
40
 
39
41
  indexes.each do |index|
40
42
  chars[index] = translation.call(chars[index])
@@ -13,14 +13,18 @@ module ItaxCode
13
13
  #
14
14
  # @return [Hash]
15
15
  class Parser
16
- class NoTaxCodeError < StandardError; end
17
- class InvalidTaxCodeError < StandardError; end
16
+ Error = Class.new(StandardError)
17
+ NoTaxCodeError = Class.new(Error)
18
+ InvalidControlInternalNumberError = Class.new(Error)
19
+ InvalidTaxCodeError = Class.new(Error)
18
20
 
19
21
  def initialize(tax_code, utils = Utils.new)
20
- @tax_code = tax_code&.upcase
21
- @utils = utils
22
+ @tax_code = tax_code.upcase
22
23
  raise NoTaxCodeError if @tax_code.blank?
23
24
  raise InvalidTaxCodeError unless Validator.standard_length?(@tax_code)
25
+
26
+ @utils = utils
27
+ raise InvalidControlInternalNumberError if raw[:cin] != @utils.encode_cin(tax_code)
24
28
  end
25
29
 
26
30
  # Decodes the tax code into its components.
@@ -27,24 +27,49 @@ module ItaxCode
27
27
  %w[a e i o u]
28
28
  end
29
29
 
30
- def cin_odds
30
+ def cin
31
31
  {
32
- "0": 1, "1": 0, "2": 5, "3": 7, "4": 9, "5": 13, "6": 15, "7": 17, "8": 19, "9": 21,
33
- A: 1, B: 0, C: 5, D: 7, E: 9, F: 13, G: 15, H: 17, I: 19, J: 21, K: 2, L: 4, M: 18,
34
- N: 20, O: 11, P: 3, Q: 6, R: 8, S: 12, T: 14, U: 16, V: 10, W: 22, X: 25, Y: 24, Z: 23
35
- }
36
- end
37
-
38
- def cin_evens
39
- {
40
- "0": 0, "1": 1, "2": 2, "3": 3, "4": 4, "5": 5, "6": 6, "7": 7, "8": 8, "9": 9,
41
- A: 0, B: 1, C: 2, D: 3, E: 4, F: 5, G: 6, H: 7, I: 8, J: 9, K: 10, L: 11, M: 12, N: 13,
42
- O: 14, P: 15, Q: 16, R: 17, S: 18, T: 19, U: 20, V: 21, W: 22, X: 23, Y: 24, Z: 25
32
+ "0" => [0, 1],
33
+ "1" => [1, 0],
34
+ "2" => [2, 5],
35
+ "3" => [3, 7],
36
+ "4" => [4, 9],
37
+ "5" => [5, 13],
38
+ "6" => [6, 15],
39
+ "7" => [7, 17],
40
+ "8" => [8, 19],
41
+ "9" => [9, 21],
42
+ "A" => [0, 1],
43
+ "B" => [1, 0],
44
+ "C" => [2, 5],
45
+ "D" => [3, 7],
46
+ "E" => [4, 9],
47
+ "F" => [5, 13],
48
+ "G" => [6, 15],
49
+ "H" => [7, 17],
50
+ "I" => [8, 19],
51
+ "J" => [9, 21],
52
+ "K" => [10, 2],
53
+ "L" => [11, 4],
54
+ "M" => [12, 18],
55
+ "N" => [13, 20],
56
+ "O" => [14, 11],
57
+ "P" => [15, 3],
58
+ "Q" => [16, 6],
59
+ "R" => [17, 8],
60
+ "S" => [18, 12],
61
+ "T" => [19, 14],
62
+ "U" => [20, 16],
63
+ "V" => [21, 10],
64
+ "W" => [22, 22],
65
+ "X" => [23, 25],
66
+ "Y" => [24, 24],
67
+ "Z" => [25, 23]
43
68
  }
44
69
  end
45
70
 
46
71
  def cin_remainders
47
- "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
72
+ ("A".."Z").to_a
48
73
  end
49
74
 
50
75
  def omocodia
@@ -89,13 +114,13 @@ module ItaxCode
89
114
  end
90
115
 
91
116
  def encode_cin(code)
92
- tot = 0
117
+ cin_tot = 0
93
118
 
94
- code.chars.each_with_index do |char, index|
95
- tot += (index + 1).odd? ? cin_odds[char.to_sym] : cin_evens[char.to_sym]
119
+ code[0..14].each_char.with_index do |char, i|
120
+ cin_tot += cin[char][((i + 1) % 2).to_i]
96
121
  end
97
122
 
98
- cin_remainders[tot % 26]
123
+ cin_remainders[cin_tot % 26]
99
124
  end
100
125
 
101
126
  def cities
@@ -5,35 +5,76 @@ module ItaxCode
5
5
  #
6
6
  # @param [Hash] data The user input data
7
7
  class Validator
8
- LENGTH = 16
8
+ LENGTH = 16
9
+ REQUIRED_KEYS = %i[surname name gender birthdate birthplace].freeze
9
10
 
10
- def initialize(data = {})
11
- @encoded = Encoder.new(data).encode
11
+ # @param [String] tax_code The pre-computed tax code
12
+ # @param [Hash] data The optional user attributes
13
+ #
14
+ def initialize(tax_code, data = {})
15
+ @tax_code = tax_code
16
+ @data = data
12
17
  end
13
18
 
14
19
  class << self
15
20
  # Checks the tax code standard length against user
16
- # and business fical code standards.
21
+ # and business fiscal code standards.
17
22
  #
18
- # @param [String] code The tax code
23
+ # @param [String] tax_code The tax code
19
24
  #
20
25
  # @return [true, false]
21
- def standard_length?(code)
22
- code.length == LENGTH
26
+ def standard_length?(tax_code)
27
+ tax_code.length == LENGTH
23
28
  end
24
29
  end
25
30
 
26
- # Checks pre computed tax code validity against newly encoded tax code.
27
- #
28
- # @param [String] tax_code The pre computed tax code
31
+ # Checks pre-computed tax code validity against newly encoded tax code.
29
32
  #
30
33
  # @return [true, false]
31
- def valid?(tax_code)
32
- encoded[0..10] == tax_code[0..10]
34
+ def valid?
35
+ encoded_tax_code == tax_code
33
36
  end
34
37
 
35
38
  private
36
39
 
37
- attr_accessor :encoded
40
+ attr_reader :tax_code, :data
41
+
42
+ # Encodes the tax code from the given 'data' hash, also backfilling missing information
43
+ # by decoding the pre-computed tax code.
44
+ #
45
+ # @return [String, nil] The encoded tax code or nil if decoding the tax code fails
46
+ def encoded_tax_code
47
+ if partial_data?
48
+ decoded_tax_code ? backfill_data! : return
49
+ end
50
+
51
+ Encoder.new(data).encode
52
+ end
53
+
54
+ # Decodes the given tax code to backfill possibly missing data in the 'data' hash.
55
+ # If the decode fails, it means that the provided tax code is not valid.
56
+ #
57
+ # @return [Hash, nil] The decoded hash or nil if the tax code is not valid
58
+ def decoded_tax_code
59
+ @decoded_tax_code ||= begin
60
+ Parser.new(tax_code).decode
61
+ rescue Parser::Error
62
+ nil
63
+ end
64
+ end
65
+
66
+ def partial_data?
67
+ REQUIRED_KEYS.any? { |required_key| data[required_key].blank? }
68
+ end
69
+
70
+ def backfill_data!
71
+ data.tap do |hash|
72
+ hash[:surname] ||= decoded_tax_code[:raw][:surname]
73
+ hash[:name] ||= decoded_tax_code[:raw][:name]
74
+ hash[:gender] ||= decoded_tax_code[:gender]
75
+ hash[:birthdate] ||= decoded_tax_code[:birthdate]
76
+ hash[:birthplace] ||= decoded_tax_code[:birthplace][:code]
77
+ end
78
+ end
38
79
  end
39
80
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ItaxCode
4
- VERSION = "0.4.0"
4
+ VERSION = "1.0.0"
5
5
  end
data/lib/itax_code.rb CHANGED
@@ -9,6 +9,8 @@ require "itax_code/parser"
9
9
  require "itax_code/validator"
10
10
 
11
11
  module ItaxCode
12
+ Error = Class.new(StandardError)
13
+
12
14
  class << self
13
15
  # Encodes user tax code.
14
16
  #
@@ -38,7 +40,7 @@ module ItaxCode
38
40
  # encoded from user informations.
39
41
  #
40
42
  # @param [String] tax_code The user tax code
41
- # @param [Hash] data The user attributes
43
+ # @param [Hash] data The optional user attributes
42
44
  #
43
45
  # @option data [String] :surname
44
46
  # @option data [String] :name
@@ -47,10 +49,8 @@ module ItaxCode
47
49
  # @option data [String] :birthplace
48
50
  #
49
51
  # @return [Boolean]
50
- def valid?(tax_code, data)
51
- Validator.new(data).valid?(tax_code)
52
+ def valid?(tax_code, data = {})
53
+ Validator.new(tax_code, data).valid?
52
54
  end
53
55
  end
54
-
55
- class Error < StandardError; end
56
56
  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.4.0
4
+ version: 1.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Matteo Rossi
8
- autorequire:
8
+ autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2023-08-08 00:00:00.000000000 Z
11
+ date: 2023-08-30 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -24,7 +24,7 @@ dependencies:
24
24
  - - ">="
25
25
  - !ruby/object:Gem::Version
26
26
  version: '0'
27
- description:
27
+ description:
28
28
  email:
29
29
  - mttrss5@gmail.com
30
30
  executables: []
@@ -64,8 +64,8 @@ metadata:
64
64
  homepage_uri: https://github.com/matteoredz/itax-code
65
65
  source_code_uri: https://github.com/matteoredz/itax-code
66
66
  changelog_uri: https://github.com/matteoredz/itax-code/CHANGELOG.md
67
- rubygems_mfa_required: 'true'
68
- post_install_message:
67
+ rubygems_mfa_required: 'false'
68
+ post_install_message:
69
69
  rdoc_options: []
70
70
  require_paths:
71
71
  - lib
@@ -80,8 +80,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
80
80
  - !ruby/object:Gem::Version
81
81
  version: '0'
82
82
  requirements: []
83
- rubygems_version: 3.4.10
84
- signing_key:
83
+ rubygems_version: 3.1.2
84
+ signing_key:
85
85
  specification_version: 4
86
86
  summary: Encode and decode Italian tax code (Codice Fiscale)
87
87
  test_files: []