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,45 @@
|
|
|
1
|
+
"""Catálogo c_Exportacion"""
|
|
2
|
+
|
|
3
|
+
import json
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class ExportacionCatalog:
|
|
8
|
+
"""Catálogo de Exportaciones del SAT (c_Exportacion)"""
|
|
9
|
+
|
|
10
|
+
_data: list[dict] | None = None
|
|
11
|
+
_by_code: dict[str, dict] | None = None
|
|
12
|
+
|
|
13
|
+
@classmethod
|
|
14
|
+
def _load_data(cls) -> None:
|
|
15
|
+
"""Carga los datos del catálogo si aún no han sido cargados"""
|
|
16
|
+
if cls._data is None:
|
|
17
|
+
path = (
|
|
18
|
+
Path(__file__).parent.parent.parent.parent.parent.parent
|
|
19
|
+
/ "shared-data"
|
|
20
|
+
/ "sat"
|
|
21
|
+
/ "cfdi_4.0"
|
|
22
|
+
/ "exportacion.json"
|
|
23
|
+
)
|
|
24
|
+
with open(path, encoding="utf-8") as f:
|
|
25
|
+
data = json.load(f)
|
|
26
|
+
# Handle both list and dict formats
|
|
27
|
+
cls._data = data if isinstance(data, list) else data.get("exportaciones", data)
|
|
28
|
+
cls._by_code = {item["code"]: item for item in cls._data}
|
|
29
|
+
|
|
30
|
+
@classmethod
|
|
31
|
+
def get_exportacion(cls, code: str) -> dict | None:
|
|
32
|
+
"""Obtiene una exportación por su código"""
|
|
33
|
+
cls._load_data()
|
|
34
|
+
return cls._by_code.get(code)
|
|
35
|
+
|
|
36
|
+
@classmethod
|
|
37
|
+
def is_valid(cls, code: str) -> bool:
|
|
38
|
+
"""Valida si un código de exportación es válido"""
|
|
39
|
+
return cls.get_exportacion(code) is not None
|
|
40
|
+
|
|
41
|
+
@classmethod
|
|
42
|
+
def get_all(cls) -> list[dict]:
|
|
43
|
+
"""Obtiene todas las exportaciones"""
|
|
44
|
+
cls._load_data()
|
|
45
|
+
return cls._data.copy()
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
"""Catálogo c_FormaPago"""
|
|
2
|
+
|
|
3
|
+
import json
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class FormaPagoCatalog:
|
|
8
|
+
"""Catálogo de Formas de Pago del SAT (c_FormaPago)"""
|
|
9
|
+
|
|
10
|
+
_data: list[dict] | None = None
|
|
11
|
+
_by_code: dict[str, dict] | None = None
|
|
12
|
+
|
|
13
|
+
@classmethod
|
|
14
|
+
def _load_data(cls) -> None:
|
|
15
|
+
"""Carga los datos del catálogo si aún no han sido cargados"""
|
|
16
|
+
if cls._data is None:
|
|
17
|
+
path = (
|
|
18
|
+
Path(__file__).parent.parent.parent.parent.parent.parent
|
|
19
|
+
/ "shared-data"
|
|
20
|
+
/ "sat"
|
|
21
|
+
/ "cfdi_4.0"
|
|
22
|
+
/ "forma_pago.json"
|
|
23
|
+
)
|
|
24
|
+
with open(path, encoding="utf-8") as f:
|
|
25
|
+
data = json.load(f)
|
|
26
|
+
# Handle both list and dict formats
|
|
27
|
+
cls._data = data if isinstance(data, list) else data.get("formas_pago", data)
|
|
28
|
+
cls._by_code = {item["code"]: item for item in cls._data}
|
|
29
|
+
|
|
30
|
+
@classmethod
|
|
31
|
+
def get_forma_pago(cls, code: str) -> dict | None:
|
|
32
|
+
"""Obtiene una forma de pago por su código"""
|
|
33
|
+
cls._load_data()
|
|
34
|
+
return cls._by_code.get(code)
|
|
35
|
+
|
|
36
|
+
@classmethod
|
|
37
|
+
def is_valid(cls, code: str) -> bool:
|
|
38
|
+
"""Valida si un código de forma de pago es válido"""
|
|
39
|
+
return cls.get_forma_pago(code) is not None
|
|
40
|
+
|
|
41
|
+
@classmethod
|
|
42
|
+
def get_all(cls) -> list[dict]:
|
|
43
|
+
"""Obtiene todas las formas de pago"""
|
|
44
|
+
cls._load_data()
|
|
45
|
+
return cls._data.copy()
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
"""Catálogo c_Impuesto"""
|
|
2
|
+
|
|
3
|
+
import json
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class ImpuestoCatalog:
|
|
8
|
+
"""Catálogo de Impuestos del SAT (c_Impuesto)"""
|
|
9
|
+
|
|
10
|
+
_data: list[dict] | None = None
|
|
11
|
+
_by_code: dict[str, dict] | None = None
|
|
12
|
+
|
|
13
|
+
@classmethod
|
|
14
|
+
def _load_data(cls) -> None:
|
|
15
|
+
"""Carga los datos del catálogo si aún no han sido cargados"""
|
|
16
|
+
if cls._data is None:
|
|
17
|
+
path = (
|
|
18
|
+
Path(__file__).parent.parent.parent.parent.parent.parent
|
|
19
|
+
/ "shared-data"
|
|
20
|
+
/ "sat"
|
|
21
|
+
/ "cfdi_4.0"
|
|
22
|
+
/ "impuesto.json"
|
|
23
|
+
)
|
|
24
|
+
with open(path, encoding="utf-8") as f:
|
|
25
|
+
data = json.load(f)
|
|
26
|
+
# Handle both list and dict formats
|
|
27
|
+
cls._data = data if isinstance(data, list) else data.get("impuestos", data)
|
|
28
|
+
cls._by_code = {item["code"]: item for item in cls._data}
|
|
29
|
+
|
|
30
|
+
@classmethod
|
|
31
|
+
def get_impuesto(cls, code: str) -> dict | None:
|
|
32
|
+
"""Obtiene un impuesto por su código"""
|
|
33
|
+
cls._load_data()
|
|
34
|
+
return cls._by_code.get(code)
|
|
35
|
+
|
|
36
|
+
@classmethod
|
|
37
|
+
def is_valid(cls, code: str) -> bool:
|
|
38
|
+
"""Valida si un código de impuesto es válido"""
|
|
39
|
+
return cls.get_impuesto(code) is not None
|
|
40
|
+
|
|
41
|
+
@classmethod
|
|
42
|
+
def supports_retention(cls, code: str) -> bool:
|
|
43
|
+
"""Valida si un impuesto soporta retención"""
|
|
44
|
+
impuesto = cls.get_impuesto(code)
|
|
45
|
+
return impuesto.get("retention", False) if impuesto else False
|
|
46
|
+
|
|
47
|
+
@classmethod
|
|
48
|
+
def supports_transfer(cls, code: str) -> bool:
|
|
49
|
+
"""Valida si un impuesto soporta traslado"""
|
|
50
|
+
impuesto = cls.get_impuesto(code)
|
|
51
|
+
return impuesto.get("transfer", False) if impuesto else False
|
|
52
|
+
|
|
53
|
+
@classmethod
|
|
54
|
+
def get_all(cls) -> list[dict]:
|
|
55
|
+
"""Obtiene todos los impuestos"""
|
|
56
|
+
cls._load_data()
|
|
57
|
+
return cls._data.copy()
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
"""Catálogo de Meses (SAT)"""
|
|
2
|
+
|
|
3
|
+
import json
|
|
4
|
+
|
|
5
|
+
from ....helpers import get_project_root
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class Meses:
|
|
9
|
+
_data = None
|
|
10
|
+
|
|
11
|
+
@classmethod
|
|
12
|
+
def _load_data(cls):
|
|
13
|
+
if cls._data is None:
|
|
14
|
+
root = get_project_root()
|
|
15
|
+
path = root / "packages" / "shared-data" / "sat" / "cfdi_4.0" / "c_Meses.json"
|
|
16
|
+
with open(path, encoding="utf-8") as f:
|
|
17
|
+
json_data = json.load(f)
|
|
18
|
+
cls._data = {item["valor"]: item for item in json_data["data"]}
|
|
19
|
+
return cls._data
|
|
20
|
+
|
|
21
|
+
@classmethod
|
|
22
|
+
def get_data(cls):
|
|
23
|
+
return cls._load_data()
|
|
24
|
+
|
|
25
|
+
@classmethod
|
|
26
|
+
def get_by_id(cls, mes_id):
|
|
27
|
+
"""Busca un mes por su ID (e.g., '01', '02')."""
|
|
28
|
+
data = cls.get_data()
|
|
29
|
+
return data.get(mes_id)
|
|
30
|
+
|
|
31
|
+
@classmethod
|
|
32
|
+
def is_valid(cls, mes_id):
|
|
33
|
+
"""Verifica si un ID de mes es válido."""
|
|
34
|
+
return mes_id in cls.get_data()
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
"""Catálogo c_MetodoPago"""
|
|
2
|
+
|
|
3
|
+
import json
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class MetodoPagoCatalog:
|
|
8
|
+
"""Catálogo de Métodos de Pago del SAT (c_MetodoPago)"""
|
|
9
|
+
|
|
10
|
+
_data: list[dict] | None = None
|
|
11
|
+
_by_code: dict[str, dict] | None = None
|
|
12
|
+
|
|
13
|
+
@classmethod
|
|
14
|
+
def _load_data(cls) -> None:
|
|
15
|
+
"""Carga los datos del catálogo si aún no han sido cargados"""
|
|
16
|
+
if cls._data is None:
|
|
17
|
+
path = (
|
|
18
|
+
Path(__file__).parent.parent.parent.parent.parent.parent
|
|
19
|
+
/ "shared-data"
|
|
20
|
+
/ "sat"
|
|
21
|
+
/ "cfdi_4.0"
|
|
22
|
+
/ "metodo_pago.json"
|
|
23
|
+
)
|
|
24
|
+
with open(path, encoding="utf-8") as f:
|
|
25
|
+
data = json.load(f)
|
|
26
|
+
# Handle both list and dict formats
|
|
27
|
+
cls._data = data if isinstance(data, list) else data.get("metodos", data)
|
|
28
|
+
cls._by_code = {item["code"]: item for item in cls._data}
|
|
29
|
+
|
|
30
|
+
@classmethod
|
|
31
|
+
def get_metodo(cls, code: str) -> dict | None:
|
|
32
|
+
"""Obtiene un método de pago por su código"""
|
|
33
|
+
cls._load_data()
|
|
34
|
+
return cls._by_code.get(code.upper())
|
|
35
|
+
|
|
36
|
+
@classmethod
|
|
37
|
+
def is_valid(cls, code: str) -> bool:
|
|
38
|
+
"""Valida si un código de método de pago es válido"""
|
|
39
|
+
return cls.get_metodo(code) is not None
|
|
40
|
+
|
|
41
|
+
@classmethod
|
|
42
|
+
def get_all(cls) -> list[dict]:
|
|
43
|
+
"""Obtiene todos los métodos de pago"""
|
|
44
|
+
cls._load_data()
|
|
45
|
+
return cls._data.copy()
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
"""Catálogo c_ObjetoImp"""
|
|
2
|
+
|
|
3
|
+
import json
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class ObjetoImpCatalog:
|
|
8
|
+
"""Catálogo de Objetos Impuestos del SAT (c_ObjetoImp)"""
|
|
9
|
+
|
|
10
|
+
_data: list[dict] | None = None
|
|
11
|
+
_by_code: dict[str, dict] | None = None
|
|
12
|
+
|
|
13
|
+
@classmethod
|
|
14
|
+
def _load_data(cls) -> None:
|
|
15
|
+
"""Carga los datos del catálogo si aún no han sido cargados"""
|
|
16
|
+
if cls._data is None:
|
|
17
|
+
path = (
|
|
18
|
+
Path(__file__).parent.parent.parent.parent.parent.parent
|
|
19
|
+
/ "shared-data"
|
|
20
|
+
/ "sat"
|
|
21
|
+
/ "cfdi_4.0"
|
|
22
|
+
/ "objeto_imp.json"
|
|
23
|
+
)
|
|
24
|
+
with open(path, encoding="utf-8") as f:
|
|
25
|
+
data = json.load(f)
|
|
26
|
+
# Handle both list and dict formats
|
|
27
|
+
cls._data = data if isinstance(data, list) else data.get("objetos", data)
|
|
28
|
+
cls._by_code = {item["code"]: item for item in cls._data}
|
|
29
|
+
|
|
30
|
+
@classmethod
|
|
31
|
+
def get_objeto(cls, code: str) -> dict | None:
|
|
32
|
+
"""Obtiene un objeto impuesto por su código"""
|
|
33
|
+
cls._load_data()
|
|
34
|
+
return cls._by_code.get(code)
|
|
35
|
+
|
|
36
|
+
@classmethod
|
|
37
|
+
def is_valid(cls, code: str) -> bool:
|
|
38
|
+
"""Valida si un código de objeto impuesto es válido"""
|
|
39
|
+
return cls.get_objeto(code) is not None
|
|
40
|
+
|
|
41
|
+
@classmethod
|
|
42
|
+
def get_all(cls) -> list[dict]:
|
|
43
|
+
"""Obtiene todos los objetos impuestos"""
|
|
44
|
+
cls._load_data()
|
|
45
|
+
return cls._data.copy()
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
"""Catálogo de Periodicidad (SAT)"""
|
|
2
|
+
|
|
3
|
+
import json
|
|
4
|
+
|
|
5
|
+
from ....helpers import get_project_root
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class Periodicidad:
|
|
9
|
+
_data = None
|
|
10
|
+
|
|
11
|
+
@classmethod
|
|
12
|
+
def _load_data(cls):
|
|
13
|
+
if cls._data is None:
|
|
14
|
+
root = get_project_root()
|
|
15
|
+
path = root / "packages" / "shared-data" / "sat" / "cfdi_4.0" / "c_Periodicidad.json"
|
|
16
|
+
with open(path, encoding="utf-8") as f:
|
|
17
|
+
json_data = json.load(f)
|
|
18
|
+
cls._data = {item["valor"]: item for item in json_data["data"]}
|
|
19
|
+
return cls._data
|
|
20
|
+
|
|
21
|
+
@classmethod
|
|
22
|
+
def get_data(cls):
|
|
23
|
+
return cls._load_data()
|
|
24
|
+
|
|
25
|
+
@classmethod
|
|
26
|
+
def get_by_id(cls, periodicidad_id):
|
|
27
|
+
"""Busca una periodicidad por su ID."""
|
|
28
|
+
data = cls.get_data()
|
|
29
|
+
return data.get(periodicidad_id)
|
|
30
|
+
|
|
31
|
+
@classmethod
|
|
32
|
+
def is_valid(cls, periodicidad_id):
|
|
33
|
+
"""Verifica si un ID de periodicidad es válido."""
|
|
34
|
+
return periodicidad_id in cls.get_data()
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
"""Catálogo c_RegimenFiscal"""
|
|
2
|
+
|
|
3
|
+
import json
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class RegimenFiscalCatalog:
|
|
8
|
+
"""Catálogo de Regímenes Fiscales del SAT (c_RegimenFiscal)"""
|
|
9
|
+
|
|
10
|
+
_data: list[dict] | None = None
|
|
11
|
+
_by_code: dict[str, dict] | None = None
|
|
12
|
+
|
|
13
|
+
@classmethod
|
|
14
|
+
def _load_data(cls) -> None:
|
|
15
|
+
"""Carga los datos del catálogo si aún no han sido cargados"""
|
|
16
|
+
if cls._data is None:
|
|
17
|
+
path = (
|
|
18
|
+
Path(__file__).parent.parent.parent.parent.parent.parent
|
|
19
|
+
/ "shared-data"
|
|
20
|
+
/ "sat"
|
|
21
|
+
/ "cfdi_4.0"
|
|
22
|
+
/ "regimen_fiscal.json"
|
|
23
|
+
)
|
|
24
|
+
with open(path, encoding="utf-8") as f:
|
|
25
|
+
data = json.load(f)
|
|
26
|
+
# Handle both list and dict formats
|
|
27
|
+
cls._data = data if isinstance(data, list) else data.get("regimenes", data)
|
|
28
|
+
cls._by_code = {item["code"]: item for item in cls._data}
|
|
29
|
+
|
|
30
|
+
@classmethod
|
|
31
|
+
def get_regimen(cls, code: str) -> dict | None:
|
|
32
|
+
"""Obtiene un régimen fiscal por su código"""
|
|
33
|
+
cls._load_data()
|
|
34
|
+
return cls._by_code.get(code)
|
|
35
|
+
|
|
36
|
+
@classmethod
|
|
37
|
+
def is_valid(cls, code: str) -> bool:
|
|
38
|
+
"""Valida si un código de régimen fiscal es válido"""
|
|
39
|
+
return cls.get_regimen(code) is not None
|
|
40
|
+
|
|
41
|
+
@classmethod
|
|
42
|
+
def is_valid_for_persona_fisica(cls, code: str) -> bool:
|
|
43
|
+
"""Valida si un régimen es válido para persona física"""
|
|
44
|
+
regimen = cls.get_regimen(code)
|
|
45
|
+
return regimen.get("fisica", False) if regimen else False
|
|
46
|
+
|
|
47
|
+
@classmethod
|
|
48
|
+
def is_valid_for_persona_moral(cls, code: str) -> bool:
|
|
49
|
+
"""Valida si un régimen es válido para persona moral"""
|
|
50
|
+
regimen = cls.get_regimen(code)
|
|
51
|
+
return regimen.get("moral", False) if regimen else False
|
|
52
|
+
|
|
53
|
+
@classmethod
|
|
54
|
+
def get_all(cls) -> list[dict]:
|
|
55
|
+
"""Obtiene todos los regímenes fiscales"""
|
|
56
|
+
cls._load_data()
|
|
57
|
+
return cls._data.copy()
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
"""Catálogo de Tasa o Cuota (SAT)"""
|
|
2
|
+
|
|
3
|
+
import json
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class TasaOCuota:
|
|
8
|
+
_data = None
|
|
9
|
+
|
|
10
|
+
@classmethod
|
|
11
|
+
def _load_data(cls):
|
|
12
|
+
if cls._data is None:
|
|
13
|
+
path = (
|
|
14
|
+
Path(__file__).parent.parent.parent.parent.parent
|
|
15
|
+
/ "shared-data"
|
|
16
|
+
/ "sat"
|
|
17
|
+
/ "cfdi_4.0"
|
|
18
|
+
/ "c_TasaOCuota.json"
|
|
19
|
+
)
|
|
20
|
+
with open(path, encoding="utf-8") as f:
|
|
21
|
+
json_data = json.load(f)
|
|
22
|
+
# This catalog has a more complex structure, let's index by a combination of fields
|
|
23
|
+
cls._data = json_data["data"]
|
|
24
|
+
return cls._data
|
|
25
|
+
|
|
26
|
+
@classmethod
|
|
27
|
+
def get_data(cls):
|
|
28
|
+
return cls._load_data()
|
|
29
|
+
|
|
30
|
+
@classmethod
|
|
31
|
+
def get_by_range_and_tax(cls, valor_min, valor_max, impuesto, factor, trasladado, retenido):
|
|
32
|
+
"""Finds a rate based on multiple criteria."""
|
|
33
|
+
data = cls.get_data()
|
|
34
|
+
# This is a placeholder for a more complex search logic
|
|
35
|
+
return [
|
|
36
|
+
item
|
|
37
|
+
for item in data
|
|
38
|
+
if item.get("valor_mínimo") == valor_min
|
|
39
|
+
and item.get("valor_máximo") == valor_max
|
|
40
|
+
and item.get("impuesto") == impuesto
|
|
41
|
+
and item.get("factor") == factor
|
|
42
|
+
]
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
"""Catálogo c_TipoComprobante"""
|
|
2
|
+
|
|
3
|
+
import json
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class TipoComprobanteCatalog:
|
|
8
|
+
"""Catálogo de Tipos de Comprobante del SAT (c_TipoComprobante)"""
|
|
9
|
+
|
|
10
|
+
_data: list[dict] | None = None
|
|
11
|
+
_by_code: dict[str, dict] | None = None
|
|
12
|
+
|
|
13
|
+
@classmethod
|
|
14
|
+
def _load_data(cls) -> None:
|
|
15
|
+
"""Carga los datos del catálogo si aún no han sido cargados"""
|
|
16
|
+
if cls._data is None:
|
|
17
|
+
path = (
|
|
18
|
+
Path(__file__).parent.parent.parent.parent.parent.parent
|
|
19
|
+
/ "shared-data"
|
|
20
|
+
/ "sat"
|
|
21
|
+
/ "cfdi_4.0"
|
|
22
|
+
/ "tipo_comprobante.json"
|
|
23
|
+
)
|
|
24
|
+
with open(path, encoding="utf-8") as f:
|
|
25
|
+
data = json.load(f)
|
|
26
|
+
# Handle both list and dict formats
|
|
27
|
+
cls._data = data if isinstance(data, list) else data.get("tipos", data)
|
|
28
|
+
cls._by_code = {item["code"]: item for item in cls._data}
|
|
29
|
+
|
|
30
|
+
@classmethod
|
|
31
|
+
def get_tipo(cls, code: str) -> dict | None:
|
|
32
|
+
"""Obtiene un tipo de comprobante por su código"""
|
|
33
|
+
cls._load_data()
|
|
34
|
+
return cls._by_code.get(code.upper())
|
|
35
|
+
|
|
36
|
+
@classmethod
|
|
37
|
+
def is_valid(cls, code: str) -> bool:
|
|
38
|
+
"""Valida si un código de tipo de comprobante es válido"""
|
|
39
|
+
return cls.get_tipo(code) is not None
|
|
40
|
+
|
|
41
|
+
@classmethod
|
|
42
|
+
def get_all(cls) -> list[dict]:
|
|
43
|
+
"""Obtiene todos los tipos de comprobante"""
|
|
44
|
+
cls._load_data()
|
|
45
|
+
return cls._data.copy()
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
"""Catálogo de Tipos de Factor (SAT)"""
|
|
2
|
+
|
|
3
|
+
import json
|
|
4
|
+
|
|
5
|
+
from ....helpers import get_project_root
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class TipoFactor:
|
|
9
|
+
_data = None
|
|
10
|
+
|
|
11
|
+
@classmethod
|
|
12
|
+
def _load_data(cls):
|
|
13
|
+
if cls._data is None:
|
|
14
|
+
root = get_project_root()
|
|
15
|
+
path = root / "packages" / "shared-data" / "sat" / "cfdi_4.0" / "c_TipoFactor.json"
|
|
16
|
+
with open(path, encoding="utf-8") as f:
|
|
17
|
+
json_data = json.load(f)
|
|
18
|
+
cls._data = {item["valor"]: item for item in json_data["data"]}
|
|
19
|
+
return cls._data
|
|
20
|
+
|
|
21
|
+
@classmethod
|
|
22
|
+
def get_data(cls):
|
|
23
|
+
return cls._load_data()
|
|
24
|
+
|
|
25
|
+
@classmethod
|
|
26
|
+
def get_by_id(cls, tipo_factor_id):
|
|
27
|
+
"""Busca un tipo de factor por su ID."""
|
|
28
|
+
data = cls.get_data()
|
|
29
|
+
return data.get(tipo_factor_id)
|
|
30
|
+
|
|
31
|
+
@classmethod
|
|
32
|
+
def is_valid(cls, tipo_factor_id):
|
|
33
|
+
"""Verifica si un ID de tipo de factor es válido."""
|
|
34
|
+
return tipo_factor_id in cls.get_data()
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
"""Catálogo c_TipoRelacion"""
|
|
2
|
+
|
|
3
|
+
import json
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class TipoRelacionCatalog:
|
|
8
|
+
"""Catálogo de Tipos de Relación del SAT (c_TipoRelacion)"""
|
|
9
|
+
|
|
10
|
+
_data: list[dict] | None = None
|
|
11
|
+
_by_code: dict[str, dict] | None = None
|
|
12
|
+
|
|
13
|
+
@classmethod
|
|
14
|
+
def _load_data(cls) -> None:
|
|
15
|
+
"""Carga los datos del catálogo si aún no han sido cargados"""
|
|
16
|
+
if cls._data is None:
|
|
17
|
+
path = (
|
|
18
|
+
Path(__file__).parent.parent.parent.parent.parent.parent
|
|
19
|
+
/ "shared-data"
|
|
20
|
+
/ "sat"
|
|
21
|
+
/ "cfdi_4.0"
|
|
22
|
+
/ "tipo_relacion.json"
|
|
23
|
+
)
|
|
24
|
+
with open(path, encoding="utf-8") as f:
|
|
25
|
+
data = json.load(f)
|
|
26
|
+
# Handle both list and dict formats
|
|
27
|
+
cls._data = data if isinstance(data, list) else data.get("tipos", data)
|
|
28
|
+
cls._by_code = {item["code"]: item for item in cls._data}
|
|
29
|
+
|
|
30
|
+
@classmethod
|
|
31
|
+
def get_tipo(cls, code: str) -> dict | None:
|
|
32
|
+
"""Obtiene un tipo de relación por su código"""
|
|
33
|
+
cls._load_data()
|
|
34
|
+
return cls._by_code.get(code)
|
|
35
|
+
|
|
36
|
+
@classmethod
|
|
37
|
+
def is_valid(cls, code: str) -> bool:
|
|
38
|
+
"""Valida si un código de tipo de relación es válido"""
|
|
39
|
+
return cls.get_tipo(code) is not None
|
|
40
|
+
|
|
41
|
+
@classmethod
|
|
42
|
+
def get_all(cls) -> list[dict]:
|
|
43
|
+
"""Obtiene todos los tipos de relación"""
|
|
44
|
+
cls._load_data()
|
|
45
|
+
return cls._data.copy()
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
"""Catálogo c_UsoCFDI"""
|
|
2
|
+
|
|
3
|
+
import json
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class UsoCFDICatalog:
|
|
8
|
+
"""Catálogo de Usos del CFDI del SAT (c_UsoCFDI)"""
|
|
9
|
+
|
|
10
|
+
_data: list[dict] | None = None
|
|
11
|
+
_by_code: dict[str, dict] | None = None
|
|
12
|
+
|
|
13
|
+
@classmethod
|
|
14
|
+
def _load_data(cls) -> None:
|
|
15
|
+
"""Carga los datos del catálogo si aún no han sido cargados"""
|
|
16
|
+
if cls._data is None:
|
|
17
|
+
path = (
|
|
18
|
+
Path(__file__).parent.parent.parent.parent.parent.parent
|
|
19
|
+
/ "shared-data"
|
|
20
|
+
/ "sat"
|
|
21
|
+
/ "cfdi_4.0"
|
|
22
|
+
/ "uso_cfdi.json"
|
|
23
|
+
)
|
|
24
|
+
with open(path, encoding="utf-8") as f:
|
|
25
|
+
data = json.load(f)
|
|
26
|
+
# Handle both list and dict formats
|
|
27
|
+
cls._data = data if isinstance(data, list) else data.get("usos", data)
|
|
28
|
+
cls._by_code = {item["code"]: item for item in cls._data}
|
|
29
|
+
|
|
30
|
+
@classmethod
|
|
31
|
+
def get_uso(cls, code: str) -> dict | None:
|
|
32
|
+
"""Obtiene un uso del CFDI por su código"""
|
|
33
|
+
cls._load_data()
|
|
34
|
+
return cls._by_code.get(code.upper())
|
|
35
|
+
|
|
36
|
+
@classmethod
|
|
37
|
+
def is_valid(cls, code: str) -> bool:
|
|
38
|
+
"""Valida si un código de uso del CFDI es válido"""
|
|
39
|
+
return cls.get_uso(code) is not None
|
|
40
|
+
|
|
41
|
+
@classmethod
|
|
42
|
+
def get_all(cls) -> list[dict]:
|
|
43
|
+
"""Obtiene todos los usos del CFDI"""
|
|
44
|
+
cls._load_data()
|
|
45
|
+
return cls._data.copy()
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Catálogos del SAT para Complemento de Comercio Exterior 2.0
|
|
3
|
+
|
|
4
|
+
Este módulo contiene los catálogos oficiales del SAT necesarios para la emisión
|
|
5
|
+
de CFDI con Complemento de Comercio Exterior versión 2.0 (vigente desde enero 18, 2024).
|
|
6
|
+
|
|
7
|
+
Catálogos incluidos:
|
|
8
|
+
- c_INCOTERM: 11 Incoterms 2020
|
|
9
|
+
- c_ClavePedimento: ~40 claves de pedimento aduanero
|
|
10
|
+
- c_UnidadAduana: ~30 unidades de medida aduanera
|
|
11
|
+
- c_MotivoTraslado: 6 motivos de traslado
|
|
12
|
+
- c_RegistroIdentTribReceptor: Tipos de identificación tributaria
|
|
13
|
+
- c_Moneda: ~180 monedas ISO 4217
|
|
14
|
+
- c_Pais: ~250 países ISO 3166-1
|
|
15
|
+
- c_Estado: Estados USA y provincias Canadá
|
|
16
|
+
- c_FraccionArancelaria: ~20,000 fracciones arancelarias TIGIE/NICO
|
|
17
|
+
"""
|
|
18
|
+
|
|
19
|
+
from .claves_pedimento import ClavePedimentoCatalog
|
|
20
|
+
from .estados import EstadoCatalog
|
|
21
|
+
from .incoterms import IncotermsValidator
|
|
22
|
+
from .monedas import MonedaCatalog
|
|
23
|
+
from .motivos_traslado import MotivoTrasladoCatalog
|
|
24
|
+
from .paises import PaisCatalog
|
|
25
|
+
from .registro_ident_trib import RegistroIdentTribCatalog
|
|
26
|
+
from .unidades_aduana import UnidadAduanaCatalog
|
|
27
|
+
from .validator import ComercioExteriorValidator
|
|
28
|
+
|
|
29
|
+
__all__ = [
|
|
30
|
+
"IncotermsValidator",
|
|
31
|
+
"ClavePedimentoCatalog",
|
|
32
|
+
"UnidadAduanaCatalog",
|
|
33
|
+
"MotivoTrasladoCatalog",
|
|
34
|
+
"RegistroIdentTribCatalog",
|
|
35
|
+
"MonedaCatalog",
|
|
36
|
+
"PaisCatalog",
|
|
37
|
+
"EstadoCatalog",
|
|
38
|
+
"ComercioExteriorValidator",
|
|
39
|
+
]
|