identificamex 0.0.2 → 0.0.3
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/.travis.yml +3 -0
- data/README.md +47 -5
- data/Rakefile +1 -1
- data/lib/identificamex.rb +26 -1
- data/lib/identificamex/nombre/mayusculas.rb +35 -0
- data/lib/identificamex/nombre/nombre_completo.rb +96 -0
- data/lib/identificamex/nombre/normalizador_apellido.rb +30 -0
- data/lib/identificamex/nombre/normalizador_cadena.rb +47 -0
- data/lib/identificamex/nombre/normalizador_nombre.rb +42 -0
- data/lib/identificamex/nombre/palabra_inconveniente.rb +55 -0
- data/lib/identificamex/nombre/razon_social.rb +92 -0
- data/lib/identificamex/rfc/homoclave.rb +209 -0
- data/lib/identificamex/rfc/rfc_base.rb +32 -0
- data/lib/identificamex/rfc/rfc_generator.rb +95 -0
- data/lib/identificamex/version.rb +1 -1
- data/lib/rfc_format_validator.rb +2 -2
- data/test/identificamex/methods_validator_test.rb +35 -0
- data/test/identificamex/nombre/nombre_completo_test.rb +64 -0
- data/test/identificamex/nombre/normalizador_apellido_test.rb +30 -0
- data/test/identificamex/nombre/normalizador_nombre_test.rb +62 -0
- data/test/identificamex/nombre/razon_social_test.rb +68 -0
- data/test/identificamex/rfc/homoclave_test.rb +24 -0
- data/test/identificamex/rfc/rfc_base_test.rb +24 -0
- data/test/identificamex/rfc/rfc_generator_test.rb +170 -0
- data/test/identificamex/rfc_format_validator_test.rb +4 -4
- data/test/test_helper.rb +7 -1
- metadata +30 -3
@@ -0,0 +1,92 @@
|
|
1
|
+
module Identificamex
|
2
|
+
module Nombre
|
3
|
+
|
4
|
+
class RazonSocial
|
5
|
+
include Mayusculas
|
6
|
+
|
7
|
+
def initialize(razon_social)
|
8
|
+
@razon_social = normalizar(razon_social)
|
9
|
+
end
|
10
|
+
|
11
|
+
def siglas
|
12
|
+
tres_letras_de_razon_social
|
13
|
+
end
|
14
|
+
|
15
|
+
def to_s
|
16
|
+
@razon_social
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
|
21
|
+
def normalizar(str)
|
22
|
+
eliminar_abreviaturas(mayusculas(str))
|
23
|
+
end
|
24
|
+
|
25
|
+
def tres_letras_de_razon_social
|
26
|
+
case palabras_a_considerar.count
|
27
|
+
when 3 then siglas_tres_palabras
|
28
|
+
when 2 then siglas_dos_palabras
|
29
|
+
else siglas_palabra_unica
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def palabras_a_considerar
|
34
|
+
@palabras_a_considerar ||= palabras_razon_social[0, 3]
|
35
|
+
end
|
36
|
+
|
37
|
+
def siglas_tres_palabras
|
38
|
+
palabras_a_considerar.map{|l| l[0]}.join
|
39
|
+
end
|
40
|
+
|
41
|
+
def siglas_dos_palabras
|
42
|
+
palabras_a_considerar[0][0] + palabras_a_considerar[1][0, 2]
|
43
|
+
end
|
44
|
+
|
45
|
+
def siglas_palabra_unica
|
46
|
+
letras = palabras_a_considerar.first[0, 3]
|
47
|
+
letras = letras + ("X" * (3 - letras.length)) if letras.length < 3
|
48
|
+
letras
|
49
|
+
end
|
50
|
+
|
51
|
+
def palabras_razon_social
|
52
|
+
@razon_social
|
53
|
+
.split
|
54
|
+
.select{|p| !palabras_especiales.member?(p) }
|
55
|
+
end
|
56
|
+
|
57
|
+
def eliminar_abreviaturas(str)
|
58
|
+
abreviaturas.each do |a|
|
59
|
+
str = str.gsub(a, '')
|
60
|
+
end
|
61
|
+
str.strip
|
62
|
+
end
|
63
|
+
|
64
|
+
def palabras_especiales
|
65
|
+
%w[DE Y DEL LOS LAS LA EL PARA EN]
|
66
|
+
end
|
67
|
+
|
68
|
+
def abreviaturas
|
69
|
+
[
|
70
|
+
/COMPAÑIA/,
|
71
|
+
/CIA/,
|
72
|
+
/\ASOCIEDAD/,
|
73
|
+
/\ASOC/,
|
74
|
+
/ S EN N ?C\z/,
|
75
|
+
/ S EN C\z/,
|
76
|
+
/ S DE R ?L\z/,
|
77
|
+
/ S EN C POR A\z/,
|
78
|
+
/ S ?A\z/,
|
79
|
+
/ S ?A DE C ?V\z/,
|
80
|
+
/ S ?N ?C\z/,
|
81
|
+
/ S ?C\z/,
|
82
|
+
/ A ?C\z/,
|
83
|
+
/ A EN P\z/,
|
84
|
+
/ S ?C ?L\z/,
|
85
|
+
/ S ?C DE R ?L DE C ?V\z/,
|
86
|
+
/ S ?C ?S\z/
|
87
|
+
]
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
end
|
92
|
+
end
|
@@ -0,0 +1,209 @@
|
|
1
|
+
module Identificamex
|
2
|
+
module Rfc
|
3
|
+
|
4
|
+
class Homoclave
|
5
|
+
|
6
|
+
def initialize(rfc_base)
|
7
|
+
@rfc_base = rfc_base
|
8
|
+
end
|
9
|
+
|
10
|
+
def siglas
|
11
|
+
homonimia + digito_verificador
|
12
|
+
end
|
13
|
+
|
14
|
+
#=================
|
15
|
+
private
|
16
|
+
#=================
|
17
|
+
|
18
|
+
def homonimia
|
19
|
+
@homonimia ||= generar_homonimia
|
20
|
+
end
|
21
|
+
|
22
|
+
def generar_homonimia
|
23
|
+
suma = map_sequential_pair(numbers){|v1, v2| to_number(v1, v2) * to_number(v2)}.inject(:+)
|
24
|
+
numero_tres_ultimos_digitos = suma.to_s[-3..-1].to_i
|
25
|
+
cosiente = numero_tres_ultimos_digitos / 34
|
26
|
+
residuo = numero_tres_ultimos_digitos % 34
|
27
|
+
[clave_diferenciadora[cosiente], clave_diferenciadora[residuo]].join
|
28
|
+
end
|
29
|
+
|
30
|
+
def map_sequential_pair(str)
|
31
|
+
size = str.size
|
32
|
+
str.each_char.each_with_index.collect do |v, i|
|
33
|
+
yield str[v], str[i + 1] if i + 1 <= size
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def to_number(*chars)
|
38
|
+
[*chars].join.to_i
|
39
|
+
end
|
40
|
+
|
41
|
+
def numbers
|
42
|
+
@numbers ||= generate_numbers
|
43
|
+
end
|
44
|
+
|
45
|
+
def generate_numbers
|
46
|
+
@rfc_base.nombre_completo
|
47
|
+
.each_char
|
48
|
+
.map{|ch| tabla_conversiones[ch]}
|
49
|
+
.unshift('0')
|
50
|
+
.join
|
51
|
+
end
|
52
|
+
|
53
|
+
def digito_verificador
|
54
|
+
residuo_digito_verificador(suma_letras_rfc(@rfc_base.siglas + homonimia))
|
55
|
+
end
|
56
|
+
|
57
|
+
def suma_letras_rfc(str)
|
58
|
+
longitud_base = 13
|
59
|
+
str = " " + str if str.length < (longitud_base - 1)
|
60
|
+
str.each_char.each_with_index.inject(0) do |total, (ch, i)|
|
61
|
+
total + (longitud_base - i) * tabla_digito_verificador[ch]
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
def residuo_digito_verificador(total)
|
66
|
+
modulo_base = 11
|
67
|
+
residuo = total % modulo_base
|
68
|
+
if residuo == 0
|
69
|
+
'0'
|
70
|
+
elsif residuo == 10 || (modulo_base - residuo) == 10
|
71
|
+
'A'
|
72
|
+
else
|
73
|
+
(modulo_base - residuo).to_s
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
def tabla_conversiones
|
78
|
+
return @tabla_conversiones if @tabla_conversiones
|
79
|
+
@tabla_conversiones = {
|
80
|
+
' ' => '00',
|
81
|
+
'0' => '00',
|
82
|
+
'1' => '01',
|
83
|
+
'2' => '02',
|
84
|
+
'3' => '03',
|
85
|
+
'4' => '04',
|
86
|
+
'5' => '05',
|
87
|
+
'6' => '06',
|
88
|
+
'7' => '07',
|
89
|
+
'8' => '08',
|
90
|
+
'9' => '09',
|
91
|
+
'&' => '10',
|
92
|
+
'A' => '11',
|
93
|
+
'B' => '12',
|
94
|
+
'C' => '13',
|
95
|
+
'D' => '14',
|
96
|
+
'E' => '15',
|
97
|
+
'F' => '16',
|
98
|
+
'G' => '17',
|
99
|
+
'H' => '18',
|
100
|
+
'I' => '19',
|
101
|
+
'J' => '21',
|
102
|
+
'K' => '22',
|
103
|
+
'L' => '23',
|
104
|
+
'M' => '24',
|
105
|
+
'N' => '25',
|
106
|
+
'O' => '26',
|
107
|
+
'P' => '27',
|
108
|
+
'Q' => '28',
|
109
|
+
'R' => '29',
|
110
|
+
'S' => '32',
|
111
|
+
'T' => '33',
|
112
|
+
'U' => '34',
|
113
|
+
'V' => '35',
|
114
|
+
'W' => '36',
|
115
|
+
'X' => '37',
|
116
|
+
'Y' => '38',
|
117
|
+
'Z' => '39',
|
118
|
+
'Ñ' => '40',
|
119
|
+
}
|
120
|
+
@tabla_conversiones.default = '0'
|
121
|
+
@tabla_conversiones
|
122
|
+
end
|
123
|
+
|
124
|
+
def clave_diferenciadora
|
125
|
+
{
|
126
|
+
0 => '1',
|
127
|
+
1 => '2',
|
128
|
+
2 => '3',
|
129
|
+
3 => '4',
|
130
|
+
4 => '5',
|
131
|
+
5 => '6',
|
132
|
+
6 => '7',
|
133
|
+
7 => '8',
|
134
|
+
8 => '9',
|
135
|
+
9 => 'A',
|
136
|
+
10 => 'B',
|
137
|
+
11 => 'C',
|
138
|
+
12 => 'D',
|
139
|
+
13 => 'E',
|
140
|
+
14 => 'F',
|
141
|
+
15 => 'G',
|
142
|
+
16 => 'H',
|
143
|
+
17 => 'I',
|
144
|
+
18 => 'J',
|
145
|
+
19 => 'K',
|
146
|
+
20 => 'L',
|
147
|
+
21 => 'M',
|
148
|
+
22 => 'N',
|
149
|
+
23 => 'P',
|
150
|
+
24 => 'Q',
|
151
|
+
25 => 'R',
|
152
|
+
26 => 'S',
|
153
|
+
27 => 'T',
|
154
|
+
28 => 'U',
|
155
|
+
29 => 'V',
|
156
|
+
30 => 'W',
|
157
|
+
31 => 'X',
|
158
|
+
32 => 'Y',
|
159
|
+
33 => 'Z',
|
160
|
+
}
|
161
|
+
end
|
162
|
+
|
163
|
+
def tabla_digito_verificador
|
164
|
+
{
|
165
|
+
'0'=> 0,
|
166
|
+
'1'=> 1,
|
167
|
+
'2'=> 2,
|
168
|
+
'3'=> 3,
|
169
|
+
'4'=> 4,
|
170
|
+
'5'=> 5,
|
171
|
+
'6'=> 6,
|
172
|
+
'7'=> 7,
|
173
|
+
'8'=> 8,
|
174
|
+
'9'=> 9,
|
175
|
+
'A'=> 10,
|
176
|
+
'B'=> 11,
|
177
|
+
'C'=> 12,
|
178
|
+
'D'=> 13,
|
179
|
+
'E'=> 14,
|
180
|
+
'F'=> 15,
|
181
|
+
'G'=> 16,
|
182
|
+
'H'=> 17,
|
183
|
+
'I'=> 18,
|
184
|
+
'J'=> 19,
|
185
|
+
'K'=> 20,
|
186
|
+
'L'=> 21,
|
187
|
+
'M'=> 22,
|
188
|
+
'N'=> 23,
|
189
|
+
'&'=> 24,
|
190
|
+
'O'=> 25,
|
191
|
+
'P'=> 26,
|
192
|
+
'Q'=> 27,
|
193
|
+
'R'=> 28,
|
194
|
+
'S'=> 29,
|
195
|
+
'T'=> 30,
|
196
|
+
'U'=> 31,
|
197
|
+
'V'=> 32,
|
198
|
+
'W'=> 33,
|
199
|
+
'X'=> 34,
|
200
|
+
'Y'=> 35,
|
201
|
+
'Z'=> 36,
|
202
|
+
' '=> 37,
|
203
|
+
'Ñ'=> 38,
|
204
|
+
}
|
205
|
+
end
|
206
|
+
end
|
207
|
+
|
208
|
+
end
|
209
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
module Identificamex
|
2
|
+
module Rfc
|
3
|
+
|
4
|
+
class RfcBase
|
5
|
+
def initialize(params)
|
6
|
+
@nombre = params[:nombre] || params[:nombre_completo] || params[:razon_social]
|
7
|
+
@fecha = params[:fecha] || params[:fecha_nacimiento] || params[:fecha_creacion]
|
8
|
+
end
|
9
|
+
|
10
|
+
def siglas
|
11
|
+
@siglas ||= generar_siglas
|
12
|
+
end
|
13
|
+
|
14
|
+
def nombre_completo
|
15
|
+
@nombre.to_s
|
16
|
+
end
|
17
|
+
|
18
|
+
#=====================
|
19
|
+
private
|
20
|
+
#=====================
|
21
|
+
|
22
|
+
def generar_siglas
|
23
|
+
@nombre.siglas + fecha_formateada
|
24
|
+
end
|
25
|
+
|
26
|
+
def fecha_formateada
|
27
|
+
@fecha.strftime('%y%m%d')
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,95 @@
|
|
1
|
+
require_relative '../nombre/nombre_completo'
|
2
|
+
require_relative '../nombre/razon_social'
|
3
|
+
require_relative 'rfc_base'
|
4
|
+
require_relative 'homoclave'
|
5
|
+
|
6
|
+
module Identificamex
|
7
|
+
module Rfc
|
8
|
+
|
9
|
+
# Clase responsable de generar un RFC. Recibe el rfc y un `hash` con los
|
10
|
+
# valores del nombre, primer apellido, segundo apellido y fecha de nacimiento
|
11
|
+
# en caso de ser una persona física, o bien, razón social y fecha de creación
|
12
|
+
# en caso de ser una persona moral.
|
13
|
+
#
|
14
|
+
# Ejemplos:
|
15
|
+
#
|
16
|
+
# generator = RfcGenerator.new(nombre: 'Juan',
|
17
|
+
# primer_apellido: 'Barrios',
|
18
|
+
# segundo_apellido: 'Fernández',
|
19
|
+
# fecha_nacimiento: Date.new(1970, 12, 13))
|
20
|
+
# generator.rfc
|
21
|
+
# # => 'BAFJ701213'
|
22
|
+
#
|
23
|
+
# validator = RfcGenerator.new(nombre: 'Juan',
|
24
|
+
# primer_apellido: 'Martínez',
|
25
|
+
# segundo_apellido: nil,
|
26
|
+
# fecha_nacimiento: Date.new(1970, 12, 13))
|
27
|
+
# generator.rfc
|
28
|
+
# # => 'MAJU701213'
|
29
|
+
#
|
30
|
+
# generator = RfcGenerator.new(razon_social: 'Sonora Industrial Azucarera, S. de R.L',
|
31
|
+
# fecha_creacion: Date.new(1983, 03, 05))
|
32
|
+
# generator.rfc
|
33
|
+
# # => 'SIA8303054L5'
|
34
|
+
#
|
35
|
+
# generator = RfcGenerator.new(razon_social: 'Los Viajes Internacionales de Marco Polo, S.A.',
|
36
|
+
# fecha_creacion: Date.new(1983, 03, 05))
|
37
|
+
# generator.rfc
|
38
|
+
# # => 'VIM8303056B6'
|
39
|
+
class RfcGenerator
|
40
|
+
|
41
|
+
def initialize(params)
|
42
|
+
@nombre_completo = build_nombre_completo(params)
|
43
|
+
@razon_social = build_razon_social(params)
|
44
|
+
@fecha_nacimiento = params[:fecha_nacimiento]
|
45
|
+
@fecha_creacion = params[:fecha_creacion]
|
46
|
+
end
|
47
|
+
|
48
|
+
def rfc
|
49
|
+
@rfc ||= generar_rfc
|
50
|
+
end
|
51
|
+
|
52
|
+
#=====================
|
53
|
+
private
|
54
|
+
#=====================
|
55
|
+
|
56
|
+
def generar_rfc
|
57
|
+
rfc_base.siglas + homoclave.siglas
|
58
|
+
end
|
59
|
+
|
60
|
+
def build_nombre_completo(params)
|
61
|
+
hash = params_for_nombre(params)
|
62
|
+
if hash.values.any?(&:present?)
|
63
|
+
::Identificamex::Nombre::NombreCompleto.new(hash)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
def build_razon_social(params)
|
68
|
+
if params[:razon_social].present?
|
69
|
+
::Identificamex::Nombre::RazonSocial.new(params[:razon_social])
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
def rfc_base
|
74
|
+
@rfc_base ||= generar_rfc_base
|
75
|
+
end
|
76
|
+
|
77
|
+
def generar_rfc_base
|
78
|
+
RfcBase.new(
|
79
|
+
nombre: @nombre_completo || @razon_social,
|
80
|
+
fecha_nacimiento: @fecha_nacimiento || @fecha_creacion
|
81
|
+
)
|
82
|
+
end
|
83
|
+
|
84
|
+
def homoclave
|
85
|
+
@homoclave ||= Homoclave.new(@rfc_base)
|
86
|
+
end
|
87
|
+
|
88
|
+
def params_for_nombre(params)
|
89
|
+
accepted_keys = %i[nombre primer_apellido segundo_apellido]
|
90
|
+
params.reject{|k, v| !(accepted_keys.member?(k)) }
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
end
|
95
|
+
end
|
data/lib/rfc_format_validator.rb
CHANGED
@@ -1,12 +1,12 @@
|
|
1
1
|
# -*- encoding : utf-8 -*-
|
2
2
|
class RfcFormatValidator < ActiveModel::EachValidator
|
3
3
|
def validate_each(object, attribute, value)
|
4
|
-
unless value =~
|
4
|
+
unless value =~ rfc_regexp
|
5
5
|
object.errors[attribute] << (options[:message] || "no es un RFC válido")
|
6
6
|
end
|
7
7
|
end
|
8
8
|
|
9
|
-
def
|
9
|
+
def rfc_regexp
|
10
10
|
if options[:force_homoclave]
|
11
11
|
/\A[A-ZÑ&]{3,4}[0-9]{2}[0-1][0-9][0-3][0-9][A-Z0-9]{3}\z/i
|
12
12
|
else
|