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.
Files changed (81) hide show
  1. catalogmx/__init__.py +56 -0
  2. catalogmx/catalogs/__init__.py +5 -0
  3. catalogmx/catalogs/banxico/__init__.py +24 -0
  4. catalogmx/catalogs/banxico/banks.py +136 -0
  5. catalogmx/catalogs/banxico/codigos_plaza.py +287 -0
  6. catalogmx/catalogs/banxico/instituciones_financieras.py +338 -0
  7. catalogmx/catalogs/banxico/monedas_divisas.py +386 -0
  8. catalogmx/catalogs/banxico/udis.py +279 -0
  9. catalogmx/catalogs/ift/__init__.py +15 -0
  10. catalogmx/catalogs/ift/codigos_lada.py +426 -0
  11. catalogmx/catalogs/ift/operadores_moviles.py +315 -0
  12. catalogmx/catalogs/inegi/__init__.py +21 -0
  13. catalogmx/catalogs/inegi/localidades.py +207 -0
  14. catalogmx/catalogs/inegi/municipios.py +73 -0
  15. catalogmx/catalogs/inegi/municipios_completo.py +236 -0
  16. catalogmx/catalogs/inegi/states.py +148 -0
  17. catalogmx/catalogs/mexico/__init__.py +17 -0
  18. catalogmx/catalogs/mexico/hoy_no_circula.py +215 -0
  19. catalogmx/catalogs/mexico/placas_formatos.py +184 -0
  20. catalogmx/catalogs/mexico/salarios_minimos.py +156 -0
  21. catalogmx/catalogs/mexico/uma.py +207 -0
  22. catalogmx/catalogs/sat/__init__.py +13 -0
  23. catalogmx/catalogs/sat/carta_porte/__init__.py +19 -0
  24. catalogmx/catalogs/sat/carta_porte/aeropuertos.py +76 -0
  25. catalogmx/catalogs/sat/carta_porte/carreteras.py +59 -0
  26. catalogmx/catalogs/sat/carta_porte/config_autotransporte.py +54 -0
  27. catalogmx/catalogs/sat/carta_porte/material_peligroso.py +66 -0
  28. catalogmx/catalogs/sat/carta_porte/puertos_maritimos.py +63 -0
  29. catalogmx/catalogs/sat/carta_porte/tipo_embalaje.py +48 -0
  30. catalogmx/catalogs/sat/carta_porte/tipo_permiso.py +54 -0
  31. catalogmx/catalogs/sat/cfdi_4/__init__.py +42 -0
  32. catalogmx/catalogs/sat/cfdi_4/clave_prod_serv.py +383 -0
  33. catalogmx/catalogs/sat/cfdi_4/clave_unidad.py +298 -0
  34. catalogmx/catalogs/sat/cfdi_4/exportacion.py +45 -0
  35. catalogmx/catalogs/sat/cfdi_4/forma_pago.py +45 -0
  36. catalogmx/catalogs/sat/cfdi_4/impuesto.py +57 -0
  37. catalogmx/catalogs/sat/cfdi_4/meses.py +34 -0
  38. catalogmx/catalogs/sat/cfdi_4/metodo_pago.py +45 -0
  39. catalogmx/catalogs/sat/cfdi_4/objeto_imp.py +45 -0
  40. catalogmx/catalogs/sat/cfdi_4/periodicidad.py +34 -0
  41. catalogmx/catalogs/sat/cfdi_4/regimen_fiscal.py +57 -0
  42. catalogmx/catalogs/sat/cfdi_4/tasa_o_cuota.py +42 -0
  43. catalogmx/catalogs/sat/cfdi_4/tipo_comprobante.py +45 -0
  44. catalogmx/catalogs/sat/cfdi_4/tipo_factor.py +34 -0
  45. catalogmx/catalogs/sat/cfdi_4/tipo_relacion.py +45 -0
  46. catalogmx/catalogs/sat/cfdi_4/uso_cfdi.py +45 -0
  47. catalogmx/catalogs/sat/comercio_exterior/__init__.py +39 -0
  48. catalogmx/catalogs/sat/comercio_exterior/claves_pedimento.py +77 -0
  49. catalogmx/catalogs/sat/comercio_exterior/estados.py +122 -0
  50. catalogmx/catalogs/sat/comercio_exterior/incoterms.py +226 -0
  51. catalogmx/catalogs/sat/comercio_exterior/monedas.py +107 -0
  52. catalogmx/catalogs/sat/comercio_exterior/motivos_traslado.py +54 -0
  53. catalogmx/catalogs/sat/comercio_exterior/paises.py +88 -0
  54. catalogmx/catalogs/sat/comercio_exterior/registro_ident_trib.py +76 -0
  55. catalogmx/catalogs/sat/comercio_exterior/unidades_aduana.py +54 -0
  56. catalogmx/catalogs/sat/comercio_exterior/validator.py +212 -0
  57. catalogmx/catalogs/sat/nomina/__init__.py +19 -0
  58. catalogmx/catalogs/sat/nomina/banco.py +50 -0
  59. catalogmx/catalogs/sat/nomina/periodicidad_pago.py +48 -0
  60. catalogmx/catalogs/sat/nomina/riesgo_puesto.py +56 -0
  61. catalogmx/catalogs/sat/nomina/tipo_contrato.py +47 -0
  62. catalogmx/catalogs/sat/nomina/tipo_jornada.py +42 -0
  63. catalogmx/catalogs/sat/nomina/tipo_nomina.py +52 -0
  64. catalogmx/catalogs/sat/nomina/tipo_regimen.py +47 -0
  65. catalogmx/catalogs/sepomex/__init__.py +5 -0
  66. catalogmx/catalogs/sepomex/codigos_postales.py +184 -0
  67. catalogmx/cli.py +185 -0
  68. catalogmx/helpers.py +324 -0
  69. catalogmx/utils/text.py +55 -0
  70. catalogmx/validators/__init__.py +0 -0
  71. catalogmx/validators/clabe.py +233 -0
  72. catalogmx/validators/curp.py +623 -0
  73. catalogmx/validators/nss.py +255 -0
  74. catalogmx/validators/rfc.py +1004 -0
  75. catalogmx-0.3.0.dist-info/METADATA +644 -0
  76. catalogmx-0.3.0.dist-info/RECORD +81 -0
  77. catalogmx-0.3.0.dist-info/WHEEL +5 -0
  78. catalogmx-0.3.0.dist-info/entry_points.txt +2 -0
  79. catalogmx-0.3.0.dist-info/licenses/AUTHORS.rst +5 -0
  80. catalogmx-0.3.0.dist-info/licenses/LICENSE +19 -0
  81. 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()