itax_code 0.4.0 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
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: []