Skip to main content

Cliente en Python para la Ventanilla Única de Comercio Exterior Mexicano (VUCEM)

Project description

py-vucem

Cliente Python para la Ventanilla Única de Comercio Exterior Mexicano (VUCEM). Permite registrar Manifestaciones de Valor Electrónicas (MVE), digitalizar documentos, consultar pedimentos y generar el acuse de recepción en HTML, todo mediante los servicios SOAP oficiales de VUCEM firmados con e.firma (FIEL).

Requisitos

  • Python 3.9+
  • e.firma (FIEL) vigente de la empresa importadora (archivos .cer y .key)
  • Clave de acceso a servicios web de VUCEM (claveWS)
  • Token de Banxico SIE (opcional, para tipo de cambio automático)

Instalación

pip install py-vucem

O en modo desarrollo:

git clone https://github.com/pesatto/py_vucem
cd py_vucem
pip install -e .

Configuración inicial

La e.firma puede cargarse desde archivos en disco o desde base64 (para sistemas que almacenan la FIEL en base de datos, como Odoo o Django).

Desde archivos (uso local):

from py_vucem import VucemClient

client = VucemClient(
    cer_path="ruta/a/fiel.cer",
    key_path="ruta/a/fiel.key",
    password="tu-password-fiel",
    clave_ws="tu-clave-ws-vucem",
    rfc="TU_RFC",
)

Desde base64 (Odoo, Django, base de datos):

client = VucemClient(
    cer_b64=company.fiel_cer,       # campo Binary de Odoo u otro sistema
    key_b64=company.fiel_key,
    password=company.fiel_password,
    clave_ws=company.vucem_clave_ws,
    rfc=company.vat,
)

También puedes construir el FielHandler por separado y pasarlo directamente:

from py_vucem.utils import FielHandler

fiel = FielHandler.desde_base64(cer_b64, key_b64, password)
client = VucemClient(fiel=fiel, clave_ws="...", rfc="TU_RFC")

Importante: VUCEM requiere la e.firma (FIEL) de la empresa, no el CSD. Son archivos diferentes — el CSD es solo para firmar CFDIs.


Servicios disponibles

1. Manifestación de Valor Electrónica (MVE)

La MVE documenta el valor declarado de las mercancías importadas (Art. 59-A Ley Aduanera).

Construir y enviar una MVE

from py_vucem import VucemClient
from py_vucem.models.mv_builder import ManifestacionValor
from py_vucem.utils.banxico import BanxicoClient

banxico = BanxicoClient("tu-token-banxico")

client = VucemClient(
    cer_path="fiel.cer",
    key_path="fiel.key",
    password="password",
    clave_ws="clave_ws",
    rfc="PME241011C34",
)

# Construir el modelo
mv = ManifestacionValor("PME241011C34", banxico=banxico)

# Personas autorizadas a consultar la MV (agente aduanal)
mv.agregar_consulta("LWO041215F90", "TIPFIG.AGE")

# eDocuments relacionados (COVEs digitalizados en VUCEM)
mv.agregar_documento("03602601109K2")
mv.agregar_documento("0170261DD0RU6")

# Pedimento aduanal
mv.agregar_pedimento(pedimento="6003095", patente="3977", aduana="160")

# Factura / COVE
factura = mv.nueva_factura(
    cove="COVE2680TJDY6",
    incoterm="TIPINC.FOB",
    vinculacion=False,
    metodo="VALADU.VTM",
)

# Pagos realizados (TC se consulta automáticamente de Banxico)
factura.agregar_pago(
    fecha="2026-02-03", total=21328.00,
    forma="FORPAG.TE", moneda="USD",
)
factura.agregar_pago(
    fecha="2026-03-11", total=47613.00,
    forma="FORPAG.TE", moneda="USD",
)

# Incrementables al valor en aduana (fletes, seguros, etc.)
factura.agregar_incrementable(
    tipo="INCRE.GS", fecha="2026-03-21",
    total=1800.00, moneda="USD",
    cargo_importador=True,
)

# Enviar a VUCEM
resultado = client.registrar_manifestacion_desde_modelo(mv.to_dict())
print(resultado["numeroOperacion"])  # ej. 530502

# El XML firmado que se envió queda disponible en el resultado
Path("mv_firmado.xml").write_text(resultado["_xml"], encoding="utf-8")

Tipos de cambio

Si no configuras BanxicoClient, debes proporcionar tc= en cada pago:

mv = ManifestacionValor("PME241011C34")  # sin banxico

factura.agregar_pago(
    fecha="2026-02-03", total=21328.00,
    forma="FORPAG.TE", moneda="USD",
    tc=20.1234,  # obligatorio sin BanxicoClient
)

Con BanxicoClient, el TC FIX oficial se consulta automáticamente por fecha y moneda. Si proporcionas tc= junto con BanxicoClient, valida que tu TC no difiera más del 1% del oficial.

Tipos de pago disponibles

Método Descripción
agregar_pago() Precio ya pagado
agregar_por_pagar() Precio pendiente de pago (crédito)
agregar_compenso() Pago por compensación (intercambio de bienes/servicios)
agregar_incrementable() Fletes, seguros, cargos incrementables al valor
agregar_decrementable() Descuentos, devoluciones, conceptos decrementables

Obtener el XML

Hay dos momentos en los que puedes necesitar el XML:

# 1. Antes de enviar — para revisar la estructura o guardarlo
xml_sin_firma = client.generar_xml_mv(mv.to_dict(), con_firma=False)  # placeholders de firma
xml_firmado   = client.generar_xml_mv(mv.to_dict(), con_firma=True)   # firma FIEL real

Path("mv_firmado.xml").write_text(xml_firmado, encoding="utf-8")

# Validar contra el XSD de VUCEM
errores = client.validar_xml_mv(xml_firmado)
if errores:
    for e in errores:
        print("Error XSD:", e)

# 2. Al registrar — el XML firmado queda en resultado["_xml"]
resultado = client.registrar_manifestacion_desde_xml(xml_firmado)
print(resultado["numeroOperacion"])   # ej. 530502
Path("mv_enviada.xml").write_text(resultado["_xml"], encoding="utf-8")

Guarda siempre resultado["_xml"] junto con el numeroOperacion. Puedes necesitarlo como respaldo o para auditoría.

Generar el pre-acuse (borrador antes de enviar)

Genera el HTML del acuse con los datos del XML, sin conectarse a VUCEM. Útil para verificar que incoterms, montos y pedimentos estén correctos antes de registrar.

xml = client.generar_xml_mv(mv.to_dict(), con_firma=True)

html = client.generar_preacuse(xml, nombre_importador="PESATTO MEXICO, SA DE CV")
Path("borrador_mv.html").write_text(html, encoding="utf-8")
# Abrir en el navegador para revisar → Ctrl+P para obtener PDF

Los campos que dependen de VUCEM (eDocument, sellos, cadena original) aparecen como marcadores con la etiqueta BORRADOR. El RFC y tipo de figura de consulta se extraen directamente del XML.

Consultar una MVE registrada

# Por número de operación
data = client.consultar_manifestacion(numero_operacion=530502)

# Por número de MV (MNVA...)
data = client.consultar_manifestacion(edocument="MNVA2600GAOE4")

print(data["estatus"])       # "Aceptado"
print(data["eDocument"])     # "MNVA2600GAOE4"
print(data["fechaRegistro"]) # "2026-06-29T..."

2. Acuse de recepción de MVE

VUCEM no genera un acuse PDF automáticamente para las MVEs registradas por API — el documento debe generarse del lado del cliente con los datos del trámite.

Generar el acuse (después de registrar en VUCEM)

Solo necesitas el número de operación. El cliente realiza internamente dos consultas:

  1. Por numero_operacion → obtiene eDocument + sellos + cadena original
  2. Por eDocument → obtiene datosManifestacionValor (todos los datos de la MV)

Si el estatus no es "Aceptado", lanza ValueError.

html = client.generar_acuse(
    numero_operacion=530502,
    nombre_importador="PESATTO MEXICO, SA DE CV",
)
Path("acuse_mv.html").write_text(html, encoding="utf-8")
# Abrir en navegador → Ctrl+P → Guardar como PDF

Obtener PDF

El HTML incluye CSS @media print optimizado — el encabezado se repite en cada página y los bloques no se cortan. Para obtener PDF:

  1. Abre el .html en Chrome o Edge
  2. Ctrl+P → Destino: Guardar como PDF
  3. Sin márgenes, orientación vertical, papel Carta

Múltiples COVEs

Si la MVE tiene más de un COVE, el documento genera una página por COVE. Cada página incluye la información del COVE, sus pagos, incrementables, valor en aduana y su acuse de recepción individual.

# Con dos facturas/COVEs
factura1 = mv.nueva_factura(cove="COVE26XXXXXX1", ...)
factura2 = mv.nueva_factura(cove="COVE26XXXXXX2", ...)

# El HTML generado tendrá 2 páginas (una por COVE)
html = client.generar_acuse(numero_operacion=530502, nombre_importador="...")

3. Digitalización de documentos

Convierte documentos PDF en eDocuments registrados en VUCEM (facturas, listas de empaque, certificados, etc.).

# Ver catálogo de tipos de documento disponibles
tipos = client.consultar_tipos_documento()

# Digitalizar un PDF
with open("factura.pdf", "rb") as f:
    pdf_bytes = f.read()

resultado = client.digitalizar_documento(
    correo="contacto@empresa.com",
    id_tipo_documento="1",       # 1 = Factura comercial
    nombre_documento="Factura ST2601016",
    archivo_bytes=pdf_bytes,
    rfc_consulta="PME241011C34", # RFC autorizado a consultar
)

print(resultado["eDocument"])    # ej. "03602601109K2"
print(resultado["numeroOperacion"])

# Consultar el estatus de la digitalización
estatus = client.consultar_estatus_digitalizacion(resultado["numeroOperacion"])

El PDF debe pesar menos de 3 MB y ser un PDF válido (no escaneado como imagen sin OCR).


4. Consulta de COVEs

# Consultar un COVE por su eDocument
cove = client.consultar_cove("COVE2680TJDY6")
print(cove)

5. Consulta de pedimentos

# Listar pedimentos por aduana y fecha
pedimentos = client.listar_pedimentos(
    aduana="160",
    patente=3977,
    fecha_inicio=date(2026, 1, 1),
    fecha_fin=date(2026, 6, 30),
)

# Consultar estado de un pedimento
estado = client.consultar_estado_pedimentos(
    aduana=160, patente=3977,
    pedimento=6003095,
    numero_operacion=530502,
)

# Detalle completo del pedimento
detalle = client.consultar_pedimento_completo(
    aduana="160", patente=3977, pedimento=6003095,
)

# Consultar una partida específica
partida = client.consultar_partida(
    aduana="160", patente=3977, pedimento=6003095,
    numero_operacion=530502, numero_partida=1,
)

# Consultar remesas
remesas = client.consultar_remesas(
    aduana=160, patente=3977,
    pedimento=6003095,
    numero_operacion=530502,
)

6. Descarga de acuses PDF (eDocuments y COVEs)

# Acuse de un eDocument digitalizado
resultado = client.descargar_acuse("03602601109K2")

if resultado.get("pdf"):
    with open("acuse.pdf", "wb") as f:
        f.write(resultado["pdf"])

# Acuse de un COVE
resultado = client.descargar_acuse("COVE2680TJDY6", es_cove=True)

El servicio de acuses (ConsultaAcusesServiceWS) soporta eDocuments con formato numérico y COVEs. Los números MVE (MNVA...) no son compatibles con este servicio — para las MVE usa client.generar_acuse(numero_operacion).


Banco de México — Tipo de cambio

from py_vucem.utils.banxico import BanxicoClient

banxico = BanxicoClient("tu-token")

# TC FIX para una fecha específica
tc = banxico.tc("USD", "2026-02-03")
# Decimal('17.2532')

# Monedas soportadas
# USD, EUR, GBP, JPY, CAD, CHF, CNY

Token gratuito en: https://www.banxico.org.mx/SieAPIRest/service/v1/token

El TC FIX de Banxico es el mismo que usa el SAT para convertir montos en moneda extranjera en pedimentos y MVE (Art. 20 Ley Aduanera).


Claves de catálogos VUCEM

Incoterms (incoterm)

Clave Código
TIPINC.FOB FOB
TIPINC.CIF CIF
TIPINC.CFR CFR
TIPINC.EXW EXW
TIPINC.DAP DAP
TIPINC.DDP DDP
TIPINC.CPT CPT
TIPINC.FCA FCA

Formas de pago (forma)

Clave Descripción
FORPAG.TE Transferencia electrónica
FORPAG.CH Cheque
FORPAG.EF Efectivo
FORPAG.LC Letra de cambio
FORPAG.CC Carta de crédito
FORPAG.OT Otro (requiere especifique=)

Incrementables (tipo)

Clave Descripción
INCRE.GS Gastos de transporte, seguros y conexos
INCRE.CG Comisiones y gastos de corretaje
INCRE.CE Costo de envases o embalajes
INCRE.GT Gastos de embalaje
INCRE.MP Materiales, piezas y partes
INCRE.HM Herramientas, matrices y moldes
INCRE.TI Trabajos de ingeniería y diseño
INCRE.RD Regalías y derechos de licencia

Decrementables (tipo)

Clave Descripción
DECRE.GR Gastos realizados por cuenta del importador
DECRE.RP Gastos posteriores a la importación
DECRE.GT Transporte posteriores al punto de internación
DECRE.RC Contribuciones y cuotas compensatorias

Métodos de valoración (metodo)

Clave Descripción
VALADU.VTM Valor de transacción de mercancías
VALADU.VMI Valor de transacción de mercancías idénticas
VALADU.VMS Valor de transacción de mercancías similares
VALADU.VPU Valor de precio unitario de venta
VALADU.VR Valor reconstruido
VALADU.A78 Valor conforme al Art. 78 LA

Tipo de figura (figura en agregar_consulta)

Clave Descripción
TIPFIG.AGE Agente aduanal
TIPFIG.AAD Agencia aduanal
TIPFIG.REP Representante legal
TIPFIG.IMP Importador

Scripts de ejemplo

Los scripts en ejemplos/ muestran flujos completos listos para ejecutar:

Script Descripción
ejemplos/enviar_mv_6003095.py Construye, valida y envía una MVE completa
ejemplos/generar_preacuse_6003095.py Genera el borrador del acuse (sin VUCEM) para revisar antes de enviar
ejemplos/generar_acuse_6003095.py Genera el acuse oficial con sellos a partir del número de operación
ejemplos/consultar_mv_530488.py Consulta el estatus de una MVE
ejemplos/cargar_documentos_6003095.py Digitaliza documentos PDF en VUCEM
ejemplos/crear_pedimento_6003095.py Construye el modelo de MVE en JSON para revisión

Flujo típico:

cd py_vucem

# 1. Revisar datos antes de enviar
.\venv\Scripts\python.exe ejemplos\generar_preacuse_6003095.py

# 2. Enviar a VUCEM (guarda el XML y el numeroOperacion)
.\venv\Scripts\python.exe ejemplos\enviar_mv_6003095.py

# 3. Generar el acuse oficial
.\venv\Scripts\python.exe ejemplos\generar_acuse_6003095.py

Notas técnicas

Conectividad con VUCEM

Los servicios de VUCEM requieren configuración SSL especial (certificados legacy, TLS 1.0/1.1). La librería maneja esto internamente mediante LegacyVucemAdapter — no es necesaria ninguna configuración adicional.

WSDL remoto vs local

La librería usa WSDLs remotos cuando el servidor los sirve correctamente. Para servicios donde el XSD remoto devuelve 404 (como ConsultaManifestacionService), usa WSDLs locales empaquetados solo para validación, mientras la comunicación sigue siendo contra el endpoint en producción.

Cadena original y firma

La cadena original de la MVE usa el mismo formato numérico que el XML (máximo 3 decimales redondeados, sin ceros finales), garantizando que la firma electrónica sea válida. Este formato es equivalente al formatVucemNumber() de la implementación PHP de referencia de VUCEM.

Prerequisito para acuses de MVE

El acuse de una MVE solo se genera cuando el COVE referenciado existe y está validado en VUCEM. El COVE debe ser registrado por el agente aduanal antes de presentar la MVE.

Generación de PDF desde el acuse HTML

El HTML del acuse incluye CSS @media print optimizado. Para convertir a PDF:

  1. Abre el .html en Chrome o Edge
  2. Ctrl+P → Destino: Guardar como PDF
  3. Configura: sin márgenes, orientación vertical, papel Carta

El encabezado se repite automáticamente en cada página impresa gracias al uso de <thead> en la tabla principal — no requiere ninguna librería adicional.


Estructura del proyecto

py_vucem/
├── src/py_vucem/
│   ├── client.py                  # VucemClient — punto de entrada principal
│   ├── models/
│   │   ├── mv_builder.py          # ManifestacionValor y Factura (API fluida)
│   │   ├── mv_mapper.py           # Convierte modelo a estructura interna
│   │   ├── mv_xml.py              # Generador de XML SOAP firmado
│   │   ├── mv_xml_parser.py       # Parser inverso: XML VUCEM → modelo
│   │   └── mv_acuse_generator.py  # Generador de acuse HTML
│   ├── services/
│   │   ├── manifestacion_service.py   # Registro, consulta y acuses de MVE
│   │   ├── digitalizar_documento.py   # Digitalización de PDFs
│   │   ├── pedimentos_service.py      # Consulta de pedimentos aduaneros
│   │   └── cove_consulta.py           # Consulta de COVEs
│   └── utils/
│       ├── __init__.py            # FielHandler, LegacyVucemAdapter
│       └── banxico.py             # BanxicoClient — TC FIX oficial
├── ejemplos/                      # Scripts listos para ejecutar
├── tests/                         # Pruebas unitarias
│   └── fixtures/                  # Certificados de prueba
└── wsdl/                          # WSDLs locales de respaldo

Licencia

MIT © Fernando Ruiz — Pesatto México

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

py_vucem-0.1.4.tar.gz (4.1 MB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

py_vucem-0.1.4-py3-none-any.whl (102.7 kB view details)

Uploaded Python 3

File details

Details for the file py_vucem-0.1.4.tar.gz.

File metadata

  • Download URL: py_vucem-0.1.4.tar.gz
  • Upload date:
  • Size: 4.1 MB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.11.9

File hashes

Hashes for py_vucem-0.1.4.tar.gz
Algorithm Hash digest
SHA256 ea897427876af529d136866d40c5e848441136532e0b1a20b1c4d8005d14e312
MD5 441f7dc95a3cbe29e16b084c1ffc0f78
BLAKE2b-256 cfc41c4b61dd80dc31b2c38f111637140e5a3755efbd53e92d080f6835ecb817

See more details on using hashes here.

File details

Details for the file py_vucem-0.1.4-py3-none-any.whl.

File metadata

  • Download URL: py_vucem-0.1.4-py3-none-any.whl
  • Upload date:
  • Size: 102.7 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.11.9

File hashes

Hashes for py_vucem-0.1.4-py3-none-any.whl
Algorithm Hash digest
SHA256 948b76a10e350b4a4e11c3bb8d1a3c30aa1a1c9bd1fae4d2b7600b1031465181
MD5 2f2afe94c28b0a2077dd7c23ba7a4ab6
BLAKE2b-256 ea93c9426d7f2c76f984a04b3a3c4f7bcfa6c927dff727628ffe04a25709de1f

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page