La obligación para incorporar los siguientes complementos inicia a partir del 1 de noviembre del 2018.
Complementos para Consorcios en materia de Hidrocarburos.
El complemento para “Gastos del consorcio derivados de la Ejecución de un Contrato de Exploración o Extracción de Hidrocarburos”, incorpora la información sobre los gastos, costos e inversiones realizados por el operador del consorcio en la ejecución de un contrato de exploración o extracción de hidrocarburos.
El complemento para “Ingresos atribuibles a los Integrantes de un Consorcio derivados de la Contraprestación de un Contrato de Exploración o Extracción de Hidrocarburos”, incorpora la información sobre los ingresos atribuibles a los integrantes de un consorcio que fueron entregados al operador, los cuales derivan de la contraprestación de un contrato de exploración o extracción de hidrocarburos.
En el siguiente enlace encontrará información referente al nuevo complemento para ingresos atribuibles a los integrantes de un consorcio 1.0, además podrá consultar el estándar en donde se encuentra el apartado “Validaciones adicionales a realizar por el Proveedor” para la implementación del complemento de acuerdo a las especificaciones del SAT.
| Nombre | Documento |
|---|---|
| Estándar técnico: | 📥 Descargar |
| Catálogos: | 📥 Descargar |
| Esquema XSD: | 📥 Descargar |
| Utilerías XSLT: | 📥 Descargar |
<cfdi:Comprobante 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" Exportacion="01" Fecha="2026-03-24T10:00:43" Folio="1000" FormaPago="01" LugarExpedicion="45000" MetodoPago="PUE" Moneda="MXN" NoCertificado="30001000000500003416" Sello="NNOAzLJny/JpHbP0Bvq21fCr4TO+knHi9e2ny4G/+0NSbowgGYbaGA9cZdh6sB3UFBXHD2ytqyAkdP22dvKYWoCx9+IomB6AagewiPi49xZnjXuYOSOCdPhuqOvgK6xzvM4iI3Yapfz2ClAzk2SDlhPeWZhT4HnlF2B+atKTWuwN5jx03yXxEa46JcOEXVmAlpYY0OQI3BoUsei6Vmkly7dXIfyOvg09clkgjFs3rcW4VVwu9u5M6Zhf/xE4vzXtp4qZdNv9z3Nl3SZ4guXttIqVTqQ+Pq0xApOSPs3BtrOzKFKCsZyA1Mx8iq6H+xeC1fraqRqES8RJkloVMJOAzg==" Serie="A" SubTotal="1500.00" TipoDeComprobante="I" Total="1500.00" Version="4.0" xmlns:cfdi="http://www.sat.gob.mx/cfd/4" xmlns:ieeh="http://www.sat.gob.mx/IngresosHidrocarburos10" 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/IngresosHidrocarburos10 http://www.sat.gob.mx/sitio_internet/cfd/IngresosHidrocarburos10/IngresosHidrocarburos.xsd">
<cfdi:Emisor Nombre="ESCUELA KEMPER URGATE" RegimenFiscal="601" Rfc="EKU9003173C9"/>
<cfdi:Receptor DomicilioFiscalReceptor="45638" Nombre="CESAR OSBALDO CRUZ SOLORZANO" RegimenFiscalReceptor="616" Rfc="CUSC850516316" UsoCFDI="S01"/>
<cfdi:Conceptos>
<cfdi:Concepto Cantidad="50.00" ClaveProdServ="15101515" ClaveUnidad="K62" Descripcion="DIESEL" Importe="1500.00" NoIdentificacion="00002" ObjetoImp="01" Unidad="LITRO" ValorUnitario="30.00"/>
</cfdi:Conceptos>
<cfdi:Complemento>
<ieeh:IngresosHidrocarburos ContraprestacionPagadaOperador="1500.00" NumeroContrato="9999" Porcentaje="0.002" Version="1.0">
<ieeh:DocumentoRelacionado FechaFolioFiscalVinculado="2025-01-01" FolioFiscalVinculado="F0348620-D8FC-50A7-BE5C-42F8426070FA" Mes="01"/>
</ieeh:IngresosHidrocarburos>
</cfdi:Complemento>
</cfdi:Comprobante>
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import os
import sys
import base64
import hashlib
import importlib
from datetime import datetime
import xml.etree.ElementTree as ET
from lxml import etree as LET
from M2Crypto.RSA import load_key_string
importlib.reload(sys)
# Namespaces
NS_CFDI = "http://www.sat.gob.mx/cfd/4"
NS_IEEH = "http://www.sat.gob.mx/IngresosHidrocarburos10"
NS_XSI = "http://www.w3.org/2001/XMLSchema-instance"
ET.register_namespace("cfdi", NS_CFDI)
ET.register_namespace("ieeh", NS_IEEH)
ET.register_namespace("xsi", NS_XSI)
class crear_cadena40(object):
def __init__(self):
# Crear CFDI base
xml_str = self.creacionXML()
# Ruta absoluta del XML inicial
base_path = os.path.dirname(os.path.abspath(__file__))
xml_path = os.path.join(base_path, "CFDI40_IHC_S.xml")
# Guardar archivo base
with open(xml_path, "w", encoding="utf-8") as f:
f.write(xml_str)
print("XML SIN SELLO generado en:", xml_path)
# Cargar XSLT
self.XSLT_STYLE = LET.parse(
"/home/user/Documentos/XSLT/cadenaoriginal_4_0.xslt"
)
# Leer XML ya generado
with open(xml_path, "rb") as f:
self.xml_string = f.read()
xml_etree = LET.fromstring(self.xml_string)
# Cadena original
self.cadena_original = self.obtener_cadena_original(xml_etree)
# Sellar
self.sello = self.obtener_sello(self.cadena_original)
# Insertar sello en copia final
self.agregar_sello_al_xml(xml_etree)
# CREACIÓN DEL XML (SIN SELLO)
def creacionXML(self):
certificado_file = "/home/user/Documentos/CSD/EKU9003173C9.cer"
with open(certificado_file, "rb") as f:
certificado_data = f.read()
certificado_base64 = base64.b64encode(certificado_data).decode("utf-8")
# Obtener NoCertificado (20 dígitos)
os.system(
f'openssl x509 -inform DER -in "{certificado_file}" -noout -serial > "numero.txt"'
)
with open("numero.txt", "r") as serial_file:
serial_hex = serial_file.read().strip().replace("serial=", "")
no_certificado = bytearray.fromhex(serial_hex).decode()
print("NO_CERTIFICADO:", no_certificado)
# CREACIÓN DE COMPROBANTE
comprobante_attrib = {
"Version": "4.0",
"Serie": "A",
"Folio": "8542",
"Fecha": datetime.now().replace(microsecond=0).isoformat("T"),
"SubTotal": "850.00",
"Moneda": "MXN",
"Total": "850.00",
"TipoDeComprobante": "I",
"LugarExpedicion": "58000",
"FormaPago": "01",
"MetodoPago": "PUE",
"Exportacion": "01",
"CondicionesDePago": "CONDICIONES",
"NoCertificado": no_certificado,
"Certificado": certificado_base64,
}
Comprobante = ET.Element(f"{{{NS_CFDI}}}Comprobante", comprobante_attrib)
Comprobante.set(
f"{{{NS_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/IngresosHidrocarburos10 "
"http://www.sat.gob.mx/sitio_internet/cfd/IngresosHidrocarburos10/IngresosHidrocarburos.xsd"
)
# Emisor
ET.SubElement(
Comprobante,
f"{{{NS_CFDI}}}Emisor",
{"Rfc": "EKU9003173C9", "Nombre": "ESCUELA KEMPER URGATE", "RegimenFiscal": "601"},
)
# Receptor
ET.SubElement(
Comprobante,
f"{{{NS_CFDI}}}Receptor",
{
"Rfc": "CTE950627K46",
"Nombre": "COMERCIALIZADORA TEODORIKAS",
"DomicilioFiscalReceptor": "57740",
"RegimenFiscalReceptor": "601",
"UsoCFDI": "G03",
},
)
# Conceptos
Conceptos = ET.SubElement(Comprobante, f"{{{NS_CFDI}}}Conceptos")
ET.SubElement(
Conceptos,
f"{{{NS_CFDI}}}Concepto",
{
"Cantidad": "50.00",
"ClaveProdServ": "15101515",
"ClaveUnidad": "K62",
"Descripcion": "DIESEL",
"ValorUnitario": "17.00",
"Importe": "850.00",
"Unidad": "LITRO",
"ObjetoImp": "01",
"NoIdentificacion": "00002",
},
)
# Complemento
Complemento = ET.SubElement(Comprobante, f"{{{NS_CFDI}}}Complemento")
IEEH = ET.SubElement(
Complemento,
f"{{{NS_IEEH}}}IngresosHidrocarburos",
{
"Version": "1.0",
"ContraprestacionPagadaOperador": "850.00",
"NumeroContrato": "8889",
"Porcentaje": "0.001",
},
)
ET.SubElement(
IEEH,
f"{{{NS_IEEH}}}DocumentoRelacionado",
{
"FolioFiscalVinculado": "B888E48C-59DD-4CC6-9A81-81267F6DB665",
"FechaFolioFiscalVinculado": "2018-10-01",
"Mes": "10",
},
)
return ET.tostring(Comprobante, encoding="utf-8", method="xml").decode("utf-8")
# CADENA ORIGINAL
def obtener_cadena_original(self, xml_etree):
transform = LET.XSLT(self.XSLT_STYLE)
result = transform(xml_etree)
original_string = str(result).replace('<?xml version="1.0" encoding="UTF-8"?>', "").strip()
print("CADENA ORIGINAL:")
print(original_string)
return original_string
# SELLO DIGITAL
def obtener_sello(self, cadena_original):
key_path = "/home/user/Documentos/CSD/EKU9003173C9Key.pem"
key_pem = open(key_path).read().encode("utf-8")
rsa = load_key_string(key_pem)
sha = hashlib.sha256(cadena_original.encode("utf-8")).digest()
firma = rsa.sign(sha, "sha256")
return base64.b64encode(firma)
# INSERTAR SELLO
def agregar_sello_al_xml(self, xml_etree):
xml_etree.set("Sello", self.sello.decode("utf-8"))
xml_str = LET.tostring(xml_etree, encoding="utf-8").decode("utf-8")
with open("CFDI40_IHC.xml", "w", encoding="utf-8") as f:
f.write(xml_str)
print("XML SELLADO DE FORMA EXITOSA!!")
if __name__ == "__main__":
instancia = crear_cadena40()
<?php
date_default_timezone_set("America/Mexico_City");
error_reporting(E_ALL & ~E_WARNING);
// Rutas
$rutaCer = "/home/user/CSD/EKU9003173C9.cer"; // Ruta del certificado .cer
$rutaKey = "/home/user/Llave.pem"; // Ruta de la llave privada .key.pem
$rutaXML = "/home/user/ingresosh.xml"; // Ruta donde se guardará el XML generado
$rutaCadena = "/home/user/CadenaOriginal.txt"; // Ruta donde se guardará la Cadena Original
$rutaXSLT = "/home/user/XSLT/cadenaoriginal_4_0.xslt"; // Ruta del XSLT para generar la Cadena Original
// Crear carpeta destino si no existe
if (!file_exists(dirname($rutaXML))) mkdir(dirname($rutaXML), 0777, true);
// Certificado Base64
$certificado = base64_encode(file_get_contents($rutaCer));
// Obtener NoCertificado con HEX2BIN
$certDer = file_get_contents($rutaCer);
$certPem = "-----BEGIN CERTIFICATE-----\n" .
chunk_split(base64_encode($certDer), 64, "\n") .
"-----END CERTIFICATE-----\n";
$parsed = @openssl_x509_parse($certPem);
if ($parsed !== false && !empty($parsed['serialNumberHex'])) {
$hex = preg_replace('/\s+/', '', $parsed['serialNumberHex']);
$noCertificado = strtoupper(hex2bin($hex));
}
$ns = "http://www.sat.gob.mx/cfd/4";
$nsIngresoH = "http://www.sat.gob.mx/IngresosHidrocarburos10";
// === CREAR XML === //
$xml = new DOMDocument("1.0", "UTF-8");
$xml->formatOutput = true;
// Nodo Comprobante
$comprobante = $xml->createElementNS($ns, "cfdi:Comprobante");
$xml->appendChild($comprobante);
// Declarar namespace del complemento
$comprobante->setAttributeNS(
"http://www.w3.org/2000/xmlns/",
"xmlns:ieeh",
$nsIngresoH
);
// Namespaces obligatorios
$comprobante->setAttribute("xmlns:cfdi", $ns);
$comprobante->setAttribute("xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance");
$comprobante->setAttribute("xsi:schemaLocation",
"$ns http://www.sat.gob.mx/sitio_internet/cfd/4/cfdv40.xsd " .
"$nsIngresoH http://www.sat.gob.mx/sitio_internet/cfd/IngresosHidrocarburos10/IngresosHidrocarburos.xsd"
);
// Atributos CFDI
$comprobante->setAttribute("Version", "4.0");
$comprobante->setAttribute("Serie", "A");
$comprobante->setAttribute("Folio", "167ABC");
$comprobante->setAttribute("Fecha", date('Y-m-d\TH:i:s'));
$comprobante->setAttribute("SubTotal", "1000.00");
$comprobante->setAttribute("Total", "1120.00");
$comprobante->setAttribute("Moneda", "MXN");
$comprobante->setAttribute("TipoCambio", "1");
$comprobante->setAttribute("TipoDeComprobante", "I");
$comprobante->setAttribute("LugarExpedicion", "58000");
$comprobante->setAttribute("FormaPago", "03");
$comprobante->setAttribute("MetodoPago", "PUE");
$comprobante->setAttribute("Exportacion", "01");
if (!empty($noCertificado)) {
$comprobante->setAttribute("NoCertificado", $noCertificado);
}
$comprobante->setAttribute("Certificado", $certificado);
// Emisor
$emisor = $xml->createElementNS($ns, "cfdi:Emisor");
$emisor->setAttribute("Rfc", "EKU9003173C9");
$emisor->setAttribute("Nombre", "ESCUELA KEMPER URGATE");
$emisor->setAttribute("RegimenFiscal", "601");
$comprobante->appendChild($emisor);
// Receptor
$receptor = $xml->createElementNS($ns, "cfdi:Receptor");
$receptor->setAttribute("Rfc", "ICV060329BY0");
$receptor->setAttribute("Nombre", "INMOBILIARIA CVA");
$receptor->setAttribute("UsoCFDI", "G03");
$receptor->setAttribute("RegimenFiscalReceptor", "601");
$receptor->setAttribute("DomicilioFiscalReceptor", "33826");
$comprobante->appendChild($receptor);
// Conceptos
$conceptos = $xml->createElementNS($ns, "cfdi:Conceptos");
$concepto = $xml->createElementNS($ns, "cfdi:Concepto");
$concepto->setAttribute("ClaveProdServ", "78101802");
$concepto->setAttribute("Cantidad", "1.00");
$concepto->setAttribute("ClaveUnidad", "E48");
$concepto->setAttribute("Descripcion", "servicios de transporte");
$concepto->setAttribute("ValorUnitario", "1000.00");
$concepto->setAttribute("Importe", "1000.00");
$concepto->setAttribute("ObjetoImp", "02");
$conceptos->appendChild($concepto);
$comprobante->appendChild($conceptos);
// Impuestos del concepto
$impC = $xml->createElementNS($ns, "cfdi:Impuestos");
$tras = $xml->createElementNS($ns, "cfdi:Traslados");
$t = $xml->createElementNS($ns, "cfdi:Traslado");
$t->setAttribute("Base", "1000.00");
$t->setAttribute("Impuesto", "002");
$t->setAttribute("TipoFactor", "Tasa");
$t->setAttribute("TasaOCuota", "0.160000");
$t->setAttribute("Importe", "160.00");
$tras->appendChild($t);
// Retenciones
$retC = $xml->createElementNS($ns, "cfdi:Retenciones");
$r = $xml->createElementNS($ns, "cfdi:Retencion");
$r->setAttribute("Base", "1000.00");
$r->setAttribute("Impuesto", "002");
$r->setAttribute("TipoFactor", "Tasa");
$r->setAttribute("TasaOCuota", "0.040000");
$r->setAttribute("Importe", "40.00");
$retC->appendChild($r);
$impC->appendChild($tras);
$impC->appendChild($retC);
$concepto->appendChild($impC);
// Impuestos totales
$impTotal = $xml->createElementNS($ns, "cfdi:Impuestos");
$impTotal->setAttribute("TotalImpuestosRetenidos", "40.00");
$impTotal->setAttribute("TotalImpuestosTrasladados", "160.00");
$retencionesTotal = $xml->createElementNS($ns, "cfdi:Retenciones");
$retencionTotal = $xml->createElementNS($ns, "cfdi:Retencion");
$retencionTotal->setAttribute("Impuesto", "002");
$retencionTotal->setAttribute("Importe", "40.00");
$retencionesTotal->appendChild($retencionTotal);
$impTotal->appendChild($retencionesTotal);
$trasladosTotal = $xml->createElementNS($ns, "cfdi:Traslados");
$trasladoTotal = $xml->createElementNS($ns, "cfdi:Traslado");
$trasladoTotal->setAttribute("Base", "1000.00");
$trasladoTotal->setAttribute("Impuesto", "002");
$trasladoTotal->setAttribute("TipoFactor", "Tasa");
$trasladoTotal->setAttribute("TasaOCuota", "0.160000");
$trasladoTotal->setAttribute("Importe", "160.00");
$trasladosTotal->appendChild($trasladoTotal);
$impTotal->appendChild($trasladosTotal);
$comprobante->appendChild($impTotal);
// =================================================================
$Complemento = $xml->createElementNS($ns, "cfdi:Complemento");
$comprobante->appendChild($Complemento);
// Nodo principal del complemento
$Ingre = $xml->createElementNS($nsIngresoH, "ieeh:IngresosHidrocarburos");
$Ingre->setAttribute("ContraprestacionPagadaOperador", "850.00");
$Ingre->setAttribute("NumeroContrato", "8889");
$Ingre->setAttribute("Porcentaje", "0.001");
$Ingre->setAttribute("Version", "1.0");
$Complemento->appendChild($Ingre);
$DoctoR = $xml->createElementNS($nsIngresoH, "ieeh:DocumentoRelacionado");
$DoctoR->setAttribute("FechaFolioFiscalVinculado", "2018-10-01");
$DoctoR->setAttribute("FolioFiscalVinculado", "B888E48C-59DD-4CC6-9A81-81267F6DB665");
$DoctoR->setAttribute("Mes", "10");
$Ingre->appendChild($DoctoR);
// === 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 DIGITAL ===
$privKey = openssl_pkey_get_private(file_get_contents($rutaKey));
if (!$privKey) {
die("ERROR cargando la llave privada:\n" . openssl_error_string());
}
if (!openssl_sign($cadenaOriginal, $sello, $privKey, OPENSSL_ALGO_SHA256)) {
die("ERROR al firmar:\n" . openssl_error_string());
}
$sello = base64_encode($sello);
$comprobante->setAttribute("Sello", $sello);
// === GUARDAR XML ===
$xml->save($rutaXML);
@file_put_contents('/tmp/debug_ingresosh.xml', $xml->saveXML());
echo "\nXML sellado generado correctamente:\n$rutaXML\n";
echo "\nCadena Original generada:\n$cadenaOriginal\n";
?>