catalogmx 0.3.0__py3-none-any.whl
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.
- catalogmx/__init__.py +56 -0
- catalogmx/catalogs/__init__.py +5 -0
- catalogmx/catalogs/banxico/__init__.py +24 -0
- catalogmx/catalogs/banxico/banks.py +136 -0
- catalogmx/catalogs/banxico/codigos_plaza.py +287 -0
- catalogmx/catalogs/banxico/instituciones_financieras.py +338 -0
- catalogmx/catalogs/banxico/monedas_divisas.py +386 -0
- catalogmx/catalogs/banxico/udis.py +279 -0
- catalogmx/catalogs/ift/__init__.py +15 -0
- catalogmx/catalogs/ift/codigos_lada.py +426 -0
- catalogmx/catalogs/ift/operadores_moviles.py +315 -0
- catalogmx/catalogs/inegi/__init__.py +21 -0
- catalogmx/catalogs/inegi/localidades.py +207 -0
- catalogmx/catalogs/inegi/municipios.py +73 -0
- catalogmx/catalogs/inegi/municipios_completo.py +236 -0
- catalogmx/catalogs/inegi/states.py +148 -0
- catalogmx/catalogs/mexico/__init__.py +17 -0
- catalogmx/catalogs/mexico/hoy_no_circula.py +215 -0
- catalogmx/catalogs/mexico/placas_formatos.py +184 -0
- catalogmx/catalogs/mexico/salarios_minimos.py +156 -0
- catalogmx/catalogs/mexico/uma.py +207 -0
- catalogmx/catalogs/sat/__init__.py +13 -0
- catalogmx/catalogs/sat/carta_porte/__init__.py +19 -0
- catalogmx/catalogs/sat/carta_porte/aeropuertos.py +76 -0
- catalogmx/catalogs/sat/carta_porte/carreteras.py +59 -0
- catalogmx/catalogs/sat/carta_porte/config_autotransporte.py +54 -0
- catalogmx/catalogs/sat/carta_porte/material_peligroso.py +66 -0
- catalogmx/catalogs/sat/carta_porte/puertos_maritimos.py +63 -0
- catalogmx/catalogs/sat/carta_porte/tipo_embalaje.py +48 -0
- catalogmx/catalogs/sat/carta_porte/tipo_permiso.py +54 -0
- catalogmx/catalogs/sat/cfdi_4/__init__.py +42 -0
- catalogmx/catalogs/sat/cfdi_4/clave_prod_serv.py +383 -0
- catalogmx/catalogs/sat/cfdi_4/clave_unidad.py +298 -0
- catalogmx/catalogs/sat/cfdi_4/exportacion.py +45 -0
- catalogmx/catalogs/sat/cfdi_4/forma_pago.py +45 -0
- catalogmx/catalogs/sat/cfdi_4/impuesto.py +57 -0
- catalogmx/catalogs/sat/cfdi_4/meses.py +34 -0
- catalogmx/catalogs/sat/cfdi_4/metodo_pago.py +45 -0
- catalogmx/catalogs/sat/cfdi_4/objeto_imp.py +45 -0
- catalogmx/catalogs/sat/cfdi_4/periodicidad.py +34 -0
- catalogmx/catalogs/sat/cfdi_4/regimen_fiscal.py +57 -0
- catalogmx/catalogs/sat/cfdi_4/tasa_o_cuota.py +42 -0
- catalogmx/catalogs/sat/cfdi_4/tipo_comprobante.py +45 -0
- catalogmx/catalogs/sat/cfdi_4/tipo_factor.py +34 -0
- catalogmx/catalogs/sat/cfdi_4/tipo_relacion.py +45 -0
- catalogmx/catalogs/sat/cfdi_4/uso_cfdi.py +45 -0
- catalogmx/catalogs/sat/comercio_exterior/__init__.py +39 -0
- catalogmx/catalogs/sat/comercio_exterior/claves_pedimento.py +77 -0
- catalogmx/catalogs/sat/comercio_exterior/estados.py +122 -0
- catalogmx/catalogs/sat/comercio_exterior/incoterms.py +226 -0
- catalogmx/catalogs/sat/comercio_exterior/monedas.py +107 -0
- catalogmx/catalogs/sat/comercio_exterior/motivos_traslado.py +54 -0
- catalogmx/catalogs/sat/comercio_exterior/paises.py +88 -0
- catalogmx/catalogs/sat/comercio_exterior/registro_ident_trib.py +76 -0
- catalogmx/catalogs/sat/comercio_exterior/unidades_aduana.py +54 -0
- catalogmx/catalogs/sat/comercio_exterior/validator.py +212 -0
- catalogmx/catalogs/sat/nomina/__init__.py +19 -0
- catalogmx/catalogs/sat/nomina/banco.py +50 -0
- catalogmx/catalogs/sat/nomina/periodicidad_pago.py +48 -0
- catalogmx/catalogs/sat/nomina/riesgo_puesto.py +56 -0
- catalogmx/catalogs/sat/nomina/tipo_contrato.py +47 -0
- catalogmx/catalogs/sat/nomina/tipo_jornada.py +42 -0
- catalogmx/catalogs/sat/nomina/tipo_nomina.py +52 -0
- catalogmx/catalogs/sat/nomina/tipo_regimen.py +47 -0
- catalogmx/catalogs/sepomex/__init__.py +5 -0
- catalogmx/catalogs/sepomex/codigos_postales.py +184 -0
- catalogmx/cli.py +185 -0
- catalogmx/helpers.py +324 -0
- catalogmx/utils/text.py +55 -0
- catalogmx/validators/__init__.py +0 -0
- catalogmx/validators/clabe.py +233 -0
- catalogmx/validators/curp.py +623 -0
- catalogmx/validators/nss.py +255 -0
- catalogmx/validators/rfc.py +1004 -0
- catalogmx-0.3.0.dist-info/METADATA +644 -0
- catalogmx-0.3.0.dist-info/RECORD +81 -0
- catalogmx-0.3.0.dist-info/WHEEL +5 -0
- catalogmx-0.3.0.dist-info/entry_points.txt +2 -0
- catalogmx-0.3.0.dist-info/licenses/AUTHORS.rst +5 -0
- catalogmx-0.3.0.dist-info/licenses/LICENSE +19 -0
- catalogmx-0.3.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,255 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
NSS (Número de Seguridad Social) Validator
|
|
4
|
+
|
|
5
|
+
NSS is the 11-digit social security number issued by IMSS (Instituto Mexicano del Seguro Social).
|
|
6
|
+
|
|
7
|
+
Structure:
|
|
8
|
+
- 2 digits: Subdelegation code
|
|
9
|
+
- 2 digits: Year of registration (last 2 digits)
|
|
10
|
+
- 2 digits: Registration serial number
|
|
11
|
+
- 5 digits: Sequential number
|
|
12
|
+
- 1 digit: Check digit (modified Luhn algorithm)
|
|
13
|
+
|
|
14
|
+
Example: 12345678903
|
|
15
|
+
12: Subdelegation
|
|
16
|
+
34: Year (2034 or 1934)
|
|
17
|
+
56: Serial
|
|
18
|
+
78903: Sequential and check digit
|
|
19
|
+
|
|
20
|
+
Note: The check digit uses a modified Luhn algorithm specific to NSS.
|
|
21
|
+
"""
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class NSSException(Exception):
|
|
25
|
+
pass
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
class NSSLengthError(NSSException):
|
|
29
|
+
pass
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
class NSSStructureError(NSSException):
|
|
33
|
+
pass
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
class NSSCheckDigitError(NSSException):
|
|
37
|
+
pass
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
class NSSValidator:
|
|
41
|
+
"""
|
|
42
|
+
Validates NSS (Número de Seguridad Social) from IMSS
|
|
43
|
+
"""
|
|
44
|
+
|
|
45
|
+
LENGTH = 11
|
|
46
|
+
|
|
47
|
+
def __init__(self, nss: str | None) -> None:
|
|
48
|
+
"""
|
|
49
|
+
:param nss: The NSS number to validate
|
|
50
|
+
"""
|
|
51
|
+
self.nss = ""
|
|
52
|
+
if bool(nss) and isinstance(nss, str):
|
|
53
|
+
self.nss = nss.strip()
|
|
54
|
+
|
|
55
|
+
def validate(self) -> bool:
|
|
56
|
+
"""
|
|
57
|
+
Validates the NSS structure and check digit
|
|
58
|
+
:return: True if valid, raises exception if invalid
|
|
59
|
+
"""
|
|
60
|
+
value = self.nss
|
|
61
|
+
|
|
62
|
+
# Check length
|
|
63
|
+
if len(value) != self.LENGTH:
|
|
64
|
+
raise NSSLengthError(f"NSS length must be {self.LENGTH} digits, got {len(value)}")
|
|
65
|
+
|
|
66
|
+
# Check if all characters are digits
|
|
67
|
+
if not value.isdigit():
|
|
68
|
+
raise NSSStructureError("NSS must contain only digits")
|
|
69
|
+
|
|
70
|
+
# Validate check digit
|
|
71
|
+
if not self.verify_check_digit(value):
|
|
72
|
+
raise NSSCheckDigitError("Invalid NSS check digit")
|
|
73
|
+
|
|
74
|
+
return True
|
|
75
|
+
|
|
76
|
+
def is_valid(self) -> bool:
|
|
77
|
+
"""
|
|
78
|
+
Checks if NSS is valid without raising exceptions
|
|
79
|
+
:return: True if valid, False otherwise
|
|
80
|
+
"""
|
|
81
|
+
try:
|
|
82
|
+
return self.validate()
|
|
83
|
+
except NSSException:
|
|
84
|
+
return False
|
|
85
|
+
|
|
86
|
+
@classmethod
|
|
87
|
+
def calculate_check_digit(cls, nss_10: str) -> str:
|
|
88
|
+
"""
|
|
89
|
+
Calculates the check digit for a 10-digit NSS using modified Luhn algorithm
|
|
90
|
+
|
|
91
|
+
Algorithm (modified Luhn):
|
|
92
|
+
1. Starting from the right, multiply alternating digits by 2 and 1
|
|
93
|
+
2. If the product is > 9, sum its digits
|
|
94
|
+
3. Sum all results
|
|
95
|
+
4. The check digit is (10 - (sum % 10)) % 10
|
|
96
|
+
|
|
97
|
+
:param nss_10: First 10 digits of NSS
|
|
98
|
+
:return: Check digit (0-9)
|
|
99
|
+
"""
|
|
100
|
+
if len(nss_10) != 10:
|
|
101
|
+
raise NSSLengthError("Need exactly 10 digits to calculate check digit")
|
|
102
|
+
|
|
103
|
+
if not nss_10.isdigit():
|
|
104
|
+
raise NSSStructureError("NSS must contain only digits")
|
|
105
|
+
|
|
106
|
+
# Process digits from right to left
|
|
107
|
+
total = 0
|
|
108
|
+
for i, digit in enumerate(reversed(nss_10)):
|
|
109
|
+
n = int(digit)
|
|
110
|
+
|
|
111
|
+
# Alternate between multiplying by 2 and 1 (starting with 2 for rightmost)
|
|
112
|
+
if i % 2 == 0:
|
|
113
|
+
n = n * 2
|
|
114
|
+
# If result is > 9, sum its digits (e.g., 12 -> 1+2 = 3)
|
|
115
|
+
if n > 9:
|
|
116
|
+
n = n // 10 + n % 10
|
|
117
|
+
|
|
118
|
+
total += n
|
|
119
|
+
|
|
120
|
+
# Calculate check digit
|
|
121
|
+
check_digit = (10 - (total % 10)) % 10
|
|
122
|
+
|
|
123
|
+
return str(check_digit)
|
|
124
|
+
|
|
125
|
+
@classmethod
|
|
126
|
+
def verify_check_digit(cls, nss: str) -> bool:
|
|
127
|
+
"""
|
|
128
|
+
Verifies the check digit of an 11-digit NSS
|
|
129
|
+
|
|
130
|
+
:param nss: Complete 11-digit NSS
|
|
131
|
+
:return: True if check digit is valid, False otherwise
|
|
132
|
+
"""
|
|
133
|
+
if len(nss) != cls.LENGTH:
|
|
134
|
+
return False
|
|
135
|
+
|
|
136
|
+
calculated = cls.calculate_check_digit(nss[:10])
|
|
137
|
+
return calculated == nss[10]
|
|
138
|
+
|
|
139
|
+
def get_subdelegation(self) -> str | None:
|
|
140
|
+
"""
|
|
141
|
+
Extracts the subdelegation code (first 2 digits)
|
|
142
|
+
:return: Subdelegation code as string
|
|
143
|
+
"""
|
|
144
|
+
if len(self.nss) >= 2:
|
|
145
|
+
return self.nss[:2]
|
|
146
|
+
return None
|
|
147
|
+
|
|
148
|
+
def get_year(self) -> str | None:
|
|
149
|
+
"""
|
|
150
|
+
Extracts the registration year (digits 3-4, last 2 digits of year)
|
|
151
|
+
Note: This is ambiguous - could be 19XX or 20XX
|
|
152
|
+
:return: Year suffix as string
|
|
153
|
+
"""
|
|
154
|
+
if len(self.nss) >= 4:
|
|
155
|
+
return self.nss[2:4]
|
|
156
|
+
return None
|
|
157
|
+
|
|
158
|
+
def get_serial(self) -> str | None:
|
|
159
|
+
"""
|
|
160
|
+
Extracts the registration serial (digits 5-6)
|
|
161
|
+
:return: Serial number as string
|
|
162
|
+
"""
|
|
163
|
+
if len(self.nss) >= 6:
|
|
164
|
+
return self.nss[4:6]
|
|
165
|
+
return None
|
|
166
|
+
|
|
167
|
+
def get_sequential(self) -> str | None:
|
|
168
|
+
"""
|
|
169
|
+
Extracts the sequential number (digits 7-10)
|
|
170
|
+
:return: Sequential number as string
|
|
171
|
+
"""
|
|
172
|
+
if len(self.nss) >= 10:
|
|
173
|
+
return self.nss[6:10]
|
|
174
|
+
return None
|
|
175
|
+
|
|
176
|
+
def get_check_digit(self) -> str | None:
|
|
177
|
+
"""
|
|
178
|
+
Extracts the check digit (digit 11)
|
|
179
|
+
:return: Check digit as string
|
|
180
|
+
"""
|
|
181
|
+
if len(self.nss) == self.LENGTH:
|
|
182
|
+
return self.nss[10]
|
|
183
|
+
return None
|
|
184
|
+
|
|
185
|
+
def get_parts(self) -> dict[str, str] | None:
|
|
186
|
+
"""
|
|
187
|
+
Returns all NSS parts as a dictionary
|
|
188
|
+
:return: Dictionary with subdelegation, year, serial, sequential, check_digit
|
|
189
|
+
"""
|
|
190
|
+
if not self.is_valid():
|
|
191
|
+
return None
|
|
192
|
+
|
|
193
|
+
return {
|
|
194
|
+
"subdelegation": self.get_subdelegation(),
|
|
195
|
+
"year": self.get_year(),
|
|
196
|
+
"serial": self.get_serial(),
|
|
197
|
+
"sequential": self.get_sequential(),
|
|
198
|
+
"check_digit": self.get_check_digit(),
|
|
199
|
+
"nss": self.nss,
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
|
|
203
|
+
def validate_nss(nss: str | None) -> bool:
|
|
204
|
+
"""
|
|
205
|
+
Helper function to validate an NSS
|
|
206
|
+
|
|
207
|
+
:param nss: NSS number as string
|
|
208
|
+
:return: True if valid, False otherwise
|
|
209
|
+
"""
|
|
210
|
+
validator = NSSValidator(nss)
|
|
211
|
+
return validator.is_valid()
|
|
212
|
+
|
|
213
|
+
|
|
214
|
+
def generate_nss(
|
|
215
|
+
subdelegation: str | int, year: str | int, serial: str | int, sequential: str | int
|
|
216
|
+
) -> str:
|
|
217
|
+
"""
|
|
218
|
+
Generates a complete NSS with check digit
|
|
219
|
+
|
|
220
|
+
:param subdelegation: 2-digit subdelegation code
|
|
221
|
+
:param year: 2-digit year (last 2 digits)
|
|
222
|
+
:param serial: 2-digit serial number
|
|
223
|
+
:param sequential: 4-digit sequential number
|
|
224
|
+
:return: Complete 11-digit NSS
|
|
225
|
+
"""
|
|
226
|
+
# Ensure all parts are strings and properly formatted
|
|
227
|
+
subdelegation = str(subdelegation).zfill(2)
|
|
228
|
+
year = str(year).zfill(2)
|
|
229
|
+
serial = str(serial).zfill(2)
|
|
230
|
+
sequential = str(sequential).zfill(4)
|
|
231
|
+
|
|
232
|
+
if len(subdelegation) != 2:
|
|
233
|
+
raise NSSStructureError("Subdelegation must be 2 digits")
|
|
234
|
+
if len(year) != 2:
|
|
235
|
+
raise NSSStructureError("Year must be 2 digits")
|
|
236
|
+
if len(serial) != 2:
|
|
237
|
+
raise NSSStructureError("Serial must be 2 digits")
|
|
238
|
+
if len(sequential) != 4:
|
|
239
|
+
raise NSSStructureError("Sequential must be 4 digits")
|
|
240
|
+
|
|
241
|
+
nss_10 = subdelegation + year + serial + sequential
|
|
242
|
+
check_digit = NSSValidator.calculate_check_digit(nss_10)
|
|
243
|
+
|
|
244
|
+
return nss_10 + check_digit
|
|
245
|
+
|
|
246
|
+
|
|
247
|
+
def get_nss_info(nss: str | None) -> dict[str, str] | None:
|
|
248
|
+
"""
|
|
249
|
+
Helper function to get information from an NSS
|
|
250
|
+
|
|
251
|
+
:param nss: NSS number as string
|
|
252
|
+
:return: Dictionary with NSS parts or None if invalid
|
|
253
|
+
"""
|
|
254
|
+
validator = NSSValidator(nss)
|
|
255
|
+
return validator.get_parts()
|