Este complemento permite incluir en la factura leyendas que son consideradas en las disposiciones fiscales, distintas a las que se mencionan en el estándar técnico del comprobante.
Además, permite incorporar a una factura los siguientes datos.
Enlace directo al sitio del SAT. liga
| Nombre | Documento |
|---|---|
| Estándar del complemento: | 📥 Descargar |
| Esquema XSD: | 📥 Descargar |
| Utilería XSLT: | 📥 Descargar |
<?xml version="1.0" encoding="utf-8"?>
<cfdi:Comprobante xmlns:cfdi="http://www.sat.gob.mx/cfd/4"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.sat.gob.mx/cfd/4 http://www.sat.gob.mx/sitio_internet/cfd/4/cfdv40.xsd http://www.sat.gob.mx/leyendasFiscales http://www.sat.gob.mx/sitio_internet/cfd/leyendasFiscales/leyendasFisc.xsd"
xmlns:leyendasFisc="http://www.sat.gob.mx/leyendasFiscales" Version="4.0" Serie="Serie" Folio="202020" Fecha="2026-03-24T00:00:55" Sello="G5+vaevJY4Io9wtRSX87cK/+9FDH0PvAqRcFyLBPMf/EsbYtT6IFLMlGnDfg0b9EHvUd9n5d3+6B5dhYCy82feh1dgMnEfuGnVuLrCZrMBFfN9fTH9VPmRgB29tNjd6K1tEK/L9jZE9vig5OF5ZOp7vVwiuvQjjfkWV4j/alMwa+JEZUVtX611WpBArlDWZmxtbMe4KJazXD0K9jnITSE7k2x9bV083YSzMCm+aJC8k9daT5FOhkf9/MB0MJVIe/sFZXSbSeif1r8haflwrp8/zoxMnP3tWIvq8hp/WCf7CQYGXXFJU0W0MtNI3Tkgs/mmQRe0Jzupx2JjsXgsPBtw==" FormaPago="99" NoCertificado="30001000000500003416" Certificado="MIIFsDCCA5igAwIBAgIUMzAwMDEwMDAwMDA1MDAwMDM0MTYwDQYJKoZIhvcNAQELBQAwggErMQ8wDQYDVQQDDAZBQyBVQVQxLjAsBgNVBAoMJVNFUlZJQ0lPIERFIEFETUlOSVNUUkFDSU9OIFRSSUJVVEFSSUExGjAYBgNVBAsMEVNBVC1JRVMgQXV0aG9yaXR5MSgwJgYJKoZIhvcNAQkBFhlvc2Nhci5tYXJ0aW5lekBzYXQuZ29iLm14MR0wGwYDVQQJDBQzcmEgY2VycmFkYSBkZSBjYWxpejEOMAwGA1UEEQwFMDYzNzAxCzAJBgNVBAYTAk1YMRkwFwYDVQQIDBBDSVVEQUQgREUgTUVYSUNPMREwDwYDVQQHDAhDT1lPQUNBTjERMA8GA1UELRMIMi41LjQuNDUxJTAjBgkqhkiG9w0BCQITFnJlc3BvbnNhYmxlOiBBQ0RNQS1TQVQwHhcNMjMwNTE4MTE0MzUxWhcNMjcwNTE4MTE0MzUxWjCB1zEnMCUGA1UEAxMeRVNDVUVMQSBLRU1QRVIgVVJHQVRFIFNBIERFIENWMScwJQYDVQQpEx5FU0NVRUxBIEtFTVBFUiBVUkdBVEUgU0EgREUgQ1YxJzAlBgNVBAoTHkVTQ1VFTEEgS0VNUEVSIFVSR0FURSBTQSBERSBDVjElMCMGA1UELRMcRUtVOTAwMzE3M0M5IC8gVkFEQTgwMDkyN0RKMzEeMBwGA1UEBRMVIC8gVkFEQTgwMDkyN0hTUlNSTDA1MRMwEQYDVQQLEwpTdWN1cnNhbCAxMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAtmecO6n2GS0zL025gbHGQVxznPDICoXzR2uUngz4DqxVUC/w9cE6FxSiXm2ap8Gcjg7wmcZfm85EBaxCx/0J2u5CqnhzIoGCdhBPuhWQnIh5TLgj/X6uNquwZkKChbNe9aeFirU/JbyN7Egia9oKH9KZUsodiM/pWAH00PCtoKJ9OBcSHMq8Rqa3KKoBcfkg1ZrgueffwRLws9yOcRWLb02sDOPzGIm/jEFicVYt2Hw1qdRE5xmTZ7AGG0UHs+unkGjpCVeJ+BEBn0JPLWVvDKHZAQMj6s5Bku35+d/MyATkpOPsGT/VTnsouxekDfikJD1f7A1ZpJbqDpkJnss3vQIDAQABox0wGzAMBgNVHRMBAf8EAjAAMAsGA1UdDwQEAwIGwDANBgkqhkiG9w0BAQsFAAOCAgEAFaUgj5PqgvJigNMgtrdXZnbPfVBbukAbW4OGnUhNrA7SRAAfv2BSGk16PI0nBOr7qF2mItmBnjgEwk+DTv8Zr7w5qp7vleC6dIsZFNJoa6ZndrE/f7KO1CYruLXr5gwEkIyGfJ9NwyIagvHHMszzyHiSZIA850fWtbqtythpAliJ2jF35M5pNS+YTkRB+T6L/c6m00ymN3q9lT1rB03YywxrLreRSFZOSrbwWfg34EJbHfbFXpCSVYdJRfiVdvHnewN0r5fUlPtR9stQHyuqewzdkyb5jTTw02D2cUfL57vlPStBj7SEi3uOWvLrsiDnnCIxRMYJ2UA2ktDKHk+zWnsDmaeleSzonv2CHW42yXYPCvWi88oE1DJNYLNkIjua7MxAnkNZbScNw01A6zbLsZ3y8G6eEYnxSTRfwjd8EP4kdiHNJftm7Z4iRU7HOVh79/lRWB+gd171s3d/mI9kte3MRy6V8MMEMCAnMboGpaooYwgAmwclI2XZCczNWXfhaWe0ZS5PmytD/GDpXzkX0oEgY9K/uYo5V77NdZbGAjmyi8cE2B2ogvyaN2XfIInrZPgEffJ4AB7kFA2mwesdLOCh0BLD9itmCve3A1FGR4+stO2ANUoiI3w3Tv2yQSg4bjeDlJ08lXaaFCLW2peEXMXjQUk7fmpb5MNuOUTW6BE=" CondicionesDePago="Condiciones" SubTotal="10.00" Moneda="MXN" TipoCambio="1" Total="11.60" TipoDeComprobante="I" Exportacion="01" MetodoPago="PUE" LugarExpedicion="20000">
<cfdi:Emisor Rfc="EKU9003173C9" Nombre="ESCUELA KEMPER URGATE" RegimenFiscal="601" />
<cfdi:Receptor Rfc="ICV060329BY0" Nombre="INMOBILIARIA CVA" DomicilioFiscalReceptor="33826" RegimenFiscalReceptor="601" UsoCFDI="G01" />
<cfdi:Conceptos>
<cfdi:Concepto ClaveProdServ="50211503" Cantidad="1" ClaveUnidad="H87" Unidad="Pieza" Descripcion="Tabaco" ValorUnitario="10.00" Importe="10.00" ObjetoImp="02">
<cfdi:Impuestos>
<cfdi:Traslados>
<cfdi:Traslado Base="10.00" Impuesto="002" TipoFactor="Tasa" TasaOCuota="0.160000" Importe="1.60" />
</cfdi:Traslados>
</cfdi:Impuestos>
</cfdi:Concepto>
</cfdi:Conceptos>
<cfdi:Impuestos TotalImpuestosTrasladados="1.60">
<cfdi:Traslados>
<cfdi:Traslado Base="10.00" Impuesto="002" TipoFactor="Tasa" TasaOCuota="0.160000" Importe="1.60" />
</cfdi:Traslados>
</cfdi:Impuestos>
<cfdi:Complemento>
<leyendasFisc:LeyendasFiscales version="1.0">
<leyendasFisc:Leyenda disposicionFiscal="ISR" norma="133" textoLeyenda="Efectos fiscales al pago" />
</leyendasFisc:LeyendasFiscales>
</cfdi:Complemento>
</cfdi:Comprobante>
import base64
from lxml import etree
from datetime import datetime
from cryptography.hazmat.primitives import hashes, serialization
from cryptography.hazmat.primitives.asymmetric import padding
# ================= RUTAS =================
ruta_cer = "/ruta/certificados/EKU9003173C9.cer"
ruta_key = "/ruta/certificados/EKU9003173C9.key.pem"
ruta_xml = "/ruta/xml/cfdi_leyendas.xml"
ruta_xslt = "/ruta/xslt/cadenaoriginal_4_0.xslt"
with open(ruta_cer, "rb") as f:
cert_der = f.read()
cert_b64 = base64.b64encode(cert_der).decode()
NSMAP = {
"cfdi": "http://www.sat.gob.mx/cfd/4",
"leyendasFisc": "http://www.sat.gob.mx/leyendasFiscales",
"xsi": "http://www.w3.org/2001/XMLSchema-instance"
}
comprobante = etree.Element("{http://www.sat.gob.mx/cfd/4}Comprobante", nsmap=NSMAP)
comprobante.set("{http://www.w3.org/2001/XMLSchema-instance}schemaLocation",
"http://www.sat.gob.mx/cfd/4 http://www.sat.gob.mx/sitio_internet/cfd/4/cfdv40.xsd "
"http://www.sat.gob.mx/leyendasFiscales http://www.sat.gob.mx/sitio_internet/cfd/leyendasFiscales/leyendasFisc.xsd"
)
comprobante.set("Version", "4.0")
comprobante.set("Serie", "Serie")
comprobante.set("Folio", "2080427802")
comprobante.set("Fecha", datetime.now().strftime("%Y-%m-%dT%H:%M:%S"))
comprobante.set("FormaPago", "99")
comprobante.set("SubTotal", "200.00")
comprobante.set("Moneda", "MXN")
comprobante.set("Total", "232.00")
comprobante.set("TipoDeComprobante", "I")
comprobante.set("MetodoPago", "PUE")
comprobante.set("LugarExpedicion", "20000")
comprobante.set("Exportacion", "01")
comprobante.set("Certificado", cert_b64)
emisor = etree.SubElement(comprobante, "{http://www.sat.gob.mx/cfd/4}Emisor")
emisor.set("Rfc", "EKU9003173C9")
emisor.set("Nombre", "ESCUELA KEMPER URGATE")
emisor.set("RegimenFiscal", "601")
receptor = etree.SubElement(comprobante, "{http://www.sat.gob.mx/cfd/4}Receptor")
receptor.set("Rfc", "URE180429TM6")
receptor.set("Nombre", "UNIVERSIDAD ROBOTICA ESPAÑOLA")
receptor.set("DomicilioFiscalReceptor", "86991")
receptor.set("RegimenFiscalReceptor", "601")
receptor.set("UsoCFDI", "G01")
conceptos = etree.SubElement(comprobante, "{http://www.sat.gob.mx/cfd/4}Conceptos")
concepto = etree.SubElement(conceptos, "{http://www.sat.gob.mx/cfd/4}Concepto")
concepto.set("ClaveProdServ", "50211503")
concepto.set("Cantidad", "1")
concepto.set("ClaveUnidad", "H87")
concepto.set("Descripcion", "Cigarros")
concepto.set("ValorUnitario", "200.00")
concepto.set("Importe", "200.00")
concepto.set("ObjetoImp", "02")
# Impuestos
impuestos_c = etree.SubElement(concepto, "{http://www.sat.gob.mx/cfd/4}Impuestos")
traslados_c = etree.SubElement(impuestos_c, "{http://www.sat.gob.mx/cfd/4}Traslados")
traslado_c = etree.SubElement(traslados_c, "{http://www.sat.gob.mx/cfd/4}Traslado")
traslado_c.set("Base", "200.00")
traslado_c.set("Impuesto", "002")
traslado_c.set("TipoFactor", "Tasa")
traslado_c.set("TasaOCuota", "0.160000")
traslado_c.set("Importe", "32.00")
impuestos = etree.SubElement(comprobante, "{http://www.sat.gob.mx/cfd/4}Impuestos")
impuestos.set("TotalImpuestosTrasladados", "32.00")
traslados = etree.SubElement(impuestos, "{http://www.sat.gob.mx/cfd/4}Traslados")
traslado = etree.SubElement(traslados, "{http://www.sat.gob.mx/cfd/4}Traslado")
traslado.set("Base", "200.00")
traslado.set("Impuesto", "002")
traslado.set("TipoFactor", "Tasa")
traslado.set("TasaOCuota", "0.160000")
traslado.set("Importe", "32.00")
complemento = etree.SubElement(comprobante, "{http://www.sat.gob.mx/cfd/4}Complemento")
leyendas = etree.SubElement(complemento, "{http://www.sat.gob.mx/leyendasFiscales}LeyendasFiscales")
leyendas.set("version", "1.0")
leyenda = etree.SubElement(leyendas, "{http://www.sat.gob.mx/leyendasFiscales}Leyenda")
leyenda.set("disposicionFiscal", "ISR")
leyenda.set("norma", "133")
leyenda.set("textoLeyenda", "Efectos fiscales al pago")
xslt_root = etree.parse(ruta_xslt)
transform = etree.XSLT(xslt_root)
cadena_original = str(transform(comprobante)).strip()
with open(ruta_key, "rb") as f:
private_key = serialization.load_pem_private_key(f.read(), password=None)
firma = private_key.sign(
cadena_original.encode(),
padding.PKCS1v15(),
hashes.SHA256()
)
sello = base64.b64encode(firma).decode()
comprobante.set("Sello", sello)
xml_bytes = etree.tostring(
comprobante,
pretty_print=True,
xml_declaration=True,
encoding="UTF-8"
)
with open(ruta_xml, "wb") as f:
f.write(xml_bytes)
print("CFDI con Leyendas Fiscales generado correctamente")
<?php
date_default_timezone_set("America/Mexico_City");
error_reporting(E_ALL);
// ================= RUTAS =================
$rutaCer = "/ruta/certificados/EKU9003173C9.cer";
$rutaKey = "/ruta/certificados/EKU9003173C9.key.pem";
$rutaXML = "/ruta/xml/cfdi_leyendas.xml";
$rutaCadena= "/ruta/xml/cadena_original.txt";
$rutaXSLT = "/ruta/xslt/cadenaoriginal_4_0.xslt";
// ================= CERT =================
$certDer = file_get_contents($rutaCer);
$certificado = base64_encode($certDer);
$certPem = "-----BEGIN CERTIFICATE-----\n" .
chunk_split(base64_encode($certDer), 64, "\n") .
"-----END CERTIFICATE-----\n";
$parsed = openssl_x509_parse($certPem);
$noCertificado = $parsed['serialNumber'];
// ================= NAMESPACES =================
$nsCFDI = "http://www.sat.gob.mx/cfd/4";
$nsLeyendas = "http://www.sat.gob.mx/leyendasFiscales";
// ================= XML =================
$xml = new DOMDocument("1.0", "UTF-8");
$xml->formatOutput = true;
// ROOT
$comprobante = $xml->createElementNS($nsCFDI, "cfdi:Comprobante");
$xml->appendChild($comprobante);
// Namespaces
$comprobante->setAttribute("xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance");
$comprobante->setAttribute("xmlns:leyendasFisc", $nsLeyendas);
// SchemaLocation
$comprobante->setAttribute("xsi:schemaLocation",
"$nsCFDI http://www.sat.gob.mx/sitio_internet/cfd/4/cfdv40.xsd " .
"$nsLeyendas http://www.sat.gob.mx/sitio_internet/cfd/leyendasFiscales/leyendasFisc.xsd"
);
// ================= ATRIBUTOS (IGUAL A TU XML) =================
$comprobante->setAttribute("Version", "4.0");
$comprobante->setAttribute("Serie", "Serie");
$comprobante->setAttribute("Folio", "2080427802");
$comprobante->setAttribute("Fecha", date("Y-m-d\TH:i:s"));
$comprobante->setAttribute("FormaPago", "99");
$comprobante->setAttribute("CondicionesDePago", "CondicionesDePago");
$comprobante->setAttribute("SubTotal", "200.00");
$comprobante->setAttribute("Moneda", "MXN");
$comprobante->setAttribute("TipoCambio", "1");
$comprobante->setAttribute("Total", "232.00");
$comprobante->setAttribute("TipoDeComprobante", "I");
$comprobante->setAttribute("MetodoPago", "PUE");
$comprobante->setAttribute("LugarExpedicion", "20000");
$comprobante->setAttribute("Exportacion", "01");
$comprobante->setAttribute("NoCertificado", $noCertificado);
$comprobante->setAttribute("Certificado", $certificado);
// ================= EMISOR =================
$emisor = $xml->createElementNS($nsCFDI, "cfdi:Emisor");
$emisor->setAttribute("Rfc", "EKU9003173C9");
$emisor->setAttribute("Nombre", "ESCUELA KEMPER URGATE");
$emisor->setAttribute("RegimenFiscal", "601");
$comprobante->appendChild($emisor);
// ================= RECEPTOR =================
$receptor = $xml->createElementNS($nsCFDI, "cfdi:Receptor");
$receptor->setAttribute("Rfc", "URE180429TM6");
$receptor->setAttribute("Nombre", "UNIVERSIDAD ROBOTICA ESPAÑOLA");
$receptor->setAttribute("DomicilioFiscalReceptor", "86991");
$receptor->setAttribute("RegimenFiscalReceptor", "601");
$receptor->setAttribute("UsoCFDI", "G01");
$comprobante->appendChild($receptor);
// ================= CONCEPTOS =================
$conceptos = $xml->createElementNS($nsCFDI, "cfdi:Conceptos");
$concepto = $xml->createElementNS($nsCFDI, "cfdi:Concepto");
$concepto->setAttribute("ClaveProdServ", "50211503");
$concepto->setAttribute("NoIdentificacion", "UT421511");
$concepto->setAttribute("Cantidad", "1");
$concepto->setAttribute("ClaveUnidad", "H87");
$concepto->setAttribute("Unidad", "Pieza");
$concepto->setAttribute("Descripcion", "Cigarros");
$concepto->setAttribute("ValorUnitario", "200.00");
$concepto->setAttribute("Importe", "200.00");
$concepto->setAttribute("ObjetoImp", "02");
// IMPUESTOS CONCEPTO
$impuestosC = $xml->createElementNS($nsCFDI, "cfdi:Impuestos");
$trasladosC = $xml->createElementNS($nsCFDI, "cfdi:Traslados");
$trasladoC = $xml->createElementNS($nsCFDI, "cfdi:Traslado");
$trasladoC->setAttribute("Base", "200.00");
$trasladoC->setAttribute("Impuesto", "002");
$trasladoC->setAttribute("TipoFactor", "Tasa");
$trasladoC->setAttribute("TasaOCuota", "0.160000");
$trasladoC->setAttribute("Importe", "32.00");
$trasladosC->appendChild($trasladoC);
$impuestosC->appendChild($trasladosC);
$concepto->appendChild($impuestosC);
$conceptos->appendChild($concepto);
$comprobante->appendChild($conceptos);
// ================= IMPUESTOS =================
$impuestos = $xml->createElementNS($nsCFDI, "cfdi:Impuestos");
$impuestos->setAttribute("TotalImpuestosTrasladados", "32.00");
$traslados = $xml->createElementNS($nsCFDI, "cfdi:Traslados");
$traslado = $xml->createElementNS($nsCFDI, "cfdi:Traslado");
$traslado->setAttribute("Base", "200.00");
$traslado->setAttribute("Impuesto", "002");
$traslado->setAttribute("TipoFactor", "Tasa");
$traslado->setAttribute("TasaOCuota", "0.160000");
$traslado->setAttribute("Importe", "32.00");
$traslados->appendChild($traslado);
$impuestos->appendChild($traslados);
$comprobante->appendChild($impuestos);
// ================= COMPLEMENTO =================
$complemento = $xml->createElementNS($nsCFDI, "cfdi:Complemento");
// Leyendas Fiscales
$leyendas = $xml->createElementNS($nsLeyendas, "leyendasFisc:LeyendasFiscales");
$leyendas->setAttribute("version", "1.0");
$leyenda = $xml->createElementNS($nsLeyendas, "leyendasFisc:Leyenda");
$leyenda->setAttribute("disposicionFiscal", "ISR");
$leyenda->setAttribute("norma", "133");
$leyenda->setAttribute("textoLeyenda", "Efectos fiscales al pago");
$leyendas->appendChild($leyenda);
$complemento->appendChild($leyendas);
$comprobante->appendChild($complemento);
// ================= CADENA ORIGINAL =================
$xsl = new DOMDocument();
$xsl->load($rutaXSLT);
$proc = new XSLTProcessor();
$proc->importStylesheet($xsl);
$cadenaOriginal = trim($proc->transformToXML($xml));
file_put_contents($rutaCadena, $cadenaOriginal);
// ================= SELLO =================
$privKey = openssl_pkey_get_private(file_get_contents($rutaKey));
openssl_sign($cadenaOriginal, $sello, $privKey, OPENSSL_ALGO_SHA256);
$comprobante->setAttribute("Sello", base64_encode($sello));
// ================= GUARDAR =================
$xml->save($rutaXML);
echo "CFDI 4.0 con Leyendas Fiscales generado correctamente\n";
?>