Permite incluir información comercial extra relacionada con el sector detallista en los CFDI. Ayuda a hacer más eficiente el procesamiento de datos para la valuación de inventarios y enajenación de mercancías.
Nota: La incorporación de este complemento es totalmente opcional y sirve como una facilidad administrativa para los contribuyentes.
Enlace directo al sitio del SAT. liga
A continuación, podrá encontrar los documentos técnicos oficiales.
| Recurso | Enlace |
|---|---|
| Estándar: | 📥 Descargar |
| Esquema XSD: | 📥 Descargar |
| Utilerías XSLT: | 📥 Descargar |
<?xml version="1.0" encoding="utf-8"?>
<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="CondicionesDePago" Exportacion="01" Fecha="2026-01-14T13:55:11" Folio="Folio" FormaPago="99" LugarExpedicion="20000" MetodoPago="PPD" Moneda="MXN" NoCertificado="30001000000500003416" Sello="tBTpIRnO3TBlXKFy0hVD4PARNvYuqtRanRHrV2sosKqaJ++zIu+DnMOokEJFZEJ+CrXFZv4zD4a04lm3IQ2D1dR+HkpJ6ZixYOh5SRPKnYxWEqPYcWncJ3jhQkjPpxYKLmMqKpylsF4OB0wEHPF8Ty882BlYEjgqyV2ANZ/snTTgN87ylVmiCnn7J4aTvQf5PO/dbxBAt+OWFgNRvR0Zesnzsm+6tCO2KesuUTvRrtnJ/U8ggW9IFse1kzEoKAlEXuvOYHnEzzHQCT0bdRgit04NbI83W9DqctAcRk2TFxIXF2UuYxBycxj7FDJZE17M3T1kf5Us8qn/7CJz4S1rNg==" Serie="Serie" SubTotal="1000.00" TipoCambio="1" TipoDeComprobante="I" Total="1160.00" Version="4.0" xmlns:cfdi="http://www.sat.gob.mx/cfd/4" xmlns:detallista="http://www.sat.gob.mx/detallista" 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/detallista http://www.sat.gob.mx/sitio_internet/cfd/detallista/detallista.xsd">
<cfdi:Emisor Nombre="ESCUELA KEMPER URGATE" RegimenFiscal="601" Rfc="EKU9003173C9"/>
<cfdi:Receptor DomicilioFiscalReceptor="57740" Nombre="COMERCIALIZADORA TEODORIKAS" RegimenFiscalReceptor="601" Rfc="CTE950627K46" UsoCFDI="G03"/>
<cfdi:Conceptos>
<cfdi:Concepto Cantidad="10.00" ClaveProdServ="50202306" ClaveUnidad="H87" Descripcion="REFRESCO COLA" Importe="1000.00" NoIdentificacion="750100000001" ObjetoImp="02" Unidad="Pieza" ValorUnitario="100.00">
<cfdi:Impuestos>
<cfdi:Traslados>
<cfdi:Traslado Base="1000.00" Importe="160.00" Impuesto="002" TasaOCuota="0.160000" TipoFactor="Tasa"/>
</cfdi:Traslados>
</cfdi:Impuestos>
</cfdi:Concepto>
</cfdi:Conceptos>
<cfdi:Impuestos TotalImpuestosTrasladados="160.00">
<cfdi:Traslados>
<cfdi:Traslado Base="1000.00" Importe="160.00" Impuesto="002" TasaOCuota="0.160000" TipoFactor="Tasa"/>
</cfdi:Traslados>
</cfdi:Impuestos>
<cfdi:Complemento>
<detallista:detallista contentVersion="1.3.1" documentStatus="ORIGINAL" documentStructureVersion="AMC8.1" type="SimpleInvoiceType">
<detallista:requestForPaymentIdentification>
<detallista:entityType>INVOICE</detallista:entityType>
</detallista:requestForPaymentIdentification>
<detallista:orderIdentification>
<detallista:referenceIdentification type="ON">ORD-559988</detallista:referenceIdentification>
<detallista:ReferenceDate>2025-10-25</detallista:ReferenceDate>
</detallista:orderIdentification>
<detallista:AdditionalInformation>
<detallista:referenceIdentification type="ATZ">2</detallista:referenceIdentification>
</detallista:AdditionalInformation>
<detallista:buyer>
<detallista:gln>7504000107903</detallista:gln>
</detallista:buyer>
<detallista:seller>
<detallista:gln>7504000107903</detallista:gln>
<detallista:alternatePartyIdentification type="SELLER_ASSIGNED_IDENTIFIER_FOR_A_PARTY">998877</detallista:alternatePartyIdentification>
</detallista:seller>
<detallista:lineItem number="1" type="SimpleInvoiceLineItemType">
<detallista:tradeItemIdentification>
<detallista:gtin>750100000001</detallista:gtin>
</detallista:tradeItemIdentification>
<detallista:tradeItemDescriptionInformation language="ES">
<detallista:longText>REFRESCO</detallista:longText>
</detallista:tradeItemDescriptionInformation>
<detallista:invoicedQuantity unitOfMeasure="PCE">10.00</detallista:invoicedQuantity>
<detallista:grossPrice>
<detallista:Amount>100.00</detallista:Amount>
</detallista:grossPrice>
<detallista:netPrice>
<detallista:Amount>100.00</detallista:Amount>
</detallista:netPrice>
<detallista:totalLineAmount>
<detallista:grossAmount>
<detallista:Amount>1000.00</detallista:Amount>
</detallista:grossAmount>
<detallista:netAmount>
<detallista:Amount>1000.00</detallista:Amount>
</detallista:netAmount>
</detallista:totalLineAmount>
</detallista:lineItem>
<detallista:totalAmount>
<detallista:Amount>1000.00</detallista:Amount>
</detallista:totalAmount>
</detallista:detallista>
</cfdi:Complemento>
</cfdi:Comprobante>
<?xml version="1.0" encoding="utf-8"?>
<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=" Exportacion="01" Fecha="2026-01-14T13:55:36" Folio="1002" FormaPago="03" LugarExpedicion="58000" MetodoPago="PUE" Moneda="MXN" NoCertificado="30001000000500003416" Sello="cfUMwdckcIX/x+1HbjY+sR3yB/RUxRcJp8CJhg4QwYNOXEEA2AKdok7z2jlbHv2Sh70qjrP+fCZ6i+pOSriPKx/OIUjFRKUTo1EbKbTAfZ8Te90YQeAw0GN9ODGNCYUx3zrNFTfWVfZOfpXkwZHn2LTTRrc4Drzb0+WYy3urfVnN9IyAvgZSpHEOicrYnQjiFrmwtjupm9J8jBBU+3fzt3ohqgYDc5g/6/U/knaxDtvOqXrs8KoO/DtMUlBeq97mf+nB6RNN8iYEv/hZ3j+HQv6X23SSxx8Vyk8ynE6LZeKWwSy+K9TC+NfFVaWh6h1X3/g/kgDfLpDaYSV6OiEKtA==" Serie="DET" SubTotal="2000.00" TipoDeComprobante="I" Total="2320.00" Version="4.0" xmlns:cfdi="http://www.sat.gob.mx/cfd/4" xmlns:detallista="http://www.sat.gob.mx/detallista" 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/detallista http://www.sat.gob.mx/sitio_internet/cfd/detallista/detallista.xsd">
<cfdi:Emisor Nombre="ESCUELA KEMPER URGATE" RegimenFiscal="601" Rfc="EKU9003173C9"/>
<cfdi:Receptor DomicilioFiscalReceptor="57740" Nombre="COMERCIALIZADORA TEODORIKAS" RegimenFiscalReceptor="601" Rfc="CTE950627K46" UsoCFDI="G03"/>
<cfdi:Conceptos>
<cfdi:Concepto Cantidad="5.00" ClaveProdServ="53131600" ClaveUnidad="H87" Descripcion="SHAMPOO 1L" Importe="2000.00" NoIdentificacion="888000000002" ObjetoImp="02" Unidad="Pieza" ValorUnitario="400.00">
<cfdi:Impuestos>
<cfdi:Traslados>
<cfdi:Traslado Base="2000.00" Importe="320.00" Impuesto="002" TasaOCuota="0.160000" TipoFactor="Tasa"/>
</cfdi:Traslados>
</cfdi:Impuestos>
</cfdi:Concepto>
</cfdi:Conceptos>
<cfdi:Impuestos TotalImpuestosTrasladados="320.00">
<cfdi:Traslados>
<cfdi:Traslado Base="2000.00" Importe="320.00" Impuesto="002" TasaOCuota="0.160000" TipoFactor="Tasa"/>
</cfdi:Traslados>
</cfdi:Impuestos>
<cfdi:Complemento>
<detallista:detallista contentVersion="1.3.1" documentStatus="ORIGINAL" documentStructureVersion="AMC8.1" type="SimpleInvoiceType">
<detallista:requestForPaymentIdentification>
<detallista:entityType>INVOICE</detallista:entityType>
</detallista:requestForPaymentIdentification>
<detallista:orderIdentification>
<detallista:referenceIdentification type="ON">PO-998877</detallista:referenceIdentification>
<detallista:ReferenceDate>2025-10-20</detallista:ReferenceDate>
</detallista:orderIdentification>
<detallista:AdditionalInformation>
<detallista:referenceIdentification type="ACE">DEPTO-PERFUMERIA</detallista:referenceIdentification>
</detallista:AdditionalInformation>
<detallista:buyer>
<detallista:gln>7504000107903</detallista:gln>
</detallista:buyer>
<detallista:seller>
<detallista:gln>7504000107903</detallista:gln>
<detallista:alternatePartyIdentification type="SELLER_ASSIGNED_IDENTIFIER_FOR_A_PARTY">PROV-01</detallista:alternatePartyIdentification>
</detallista:seller>
<detallista:allowanceCharge allowanceChargeType="ALLOWANCE_GLOBAL" settlementType="BILL_BACK">
<detallista:specialServicesType>AJ</detallista:specialServicesType>
<detallista:monetaryAmountOrPercentage>
<detallista:rate base="INVOICE_VALUE">
<detallista:percentage>5.00</detallista:percentage>
</detallista:rate>
</detallista:monetaryAmountOrPercentage>
</detallista:allowanceCharge>
<detallista:lineItem number="1" type="SimpleInvoiceLineItemType">
<detallista:tradeItemIdentification>
<detallista:gtin>888000000002</detallista:gtin>
</detallista:tradeItemIdentification>
<detallista:tradeItemDescriptionInformation language="ES">
<detallista:longText>SHAMPOO 1L</detallista:longText>
</detallista:tradeItemDescriptionInformation>
<detallista:invoicedQuantity unitOfMeasure="PCE">5.00</detallista:invoicedQuantity>
<detallista:grossPrice>
<detallista:Amount>400.00</detallista:Amount>
</detallista:grossPrice>
<detallista:netPrice>
<detallista:Amount>400.00</detallista:Amount>
</detallista:netPrice>
<detallista:totalLineAmount>
<detallista:grossAmount>
<detallista:Amount>2000.00</detallista:Amount>
</detallista:grossAmount>
<detallista:netAmount>
<detallista:Amount>2000.00</detallista:Amount>
</detallista:netAmount>
</detallista:totalLineAmount>
</detallista:lineItem>
<detallista:totalAmount>
<detallista:Amount>2000.00</detallista:Amount>
</detallista:totalAmount>
<detallista:TotalAllowanceCharge allowanceOrChargeType="ALLOWANCE">
<detallista:specialServicesType>AJ</detallista:specialServicesType>
<detallista:Amount>100.00</detallista:Amount>
</detallista:TotalAllowanceCharge>
</detallista:detallista>
</cfdi:Complemento>
</cfdi:Comprobante>
<?xml version="1.0" encoding="utf-8"?>
<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=" Exportacion="01" Fecha="2026-01-14T13:56:42" Folio="1003" FormaPago="99" LugarExpedicion="58000" MetodoPago="PPD" Moneda="MXN" NoCertificado="30001000000500003416" Sello="SPNebD7hxbODf0uQ7TVzensIj63hCPxrV7e8kIITBIqnspS/tAKeiQ91eOEfBzjcpvZGOYPZdewxMpMcecjAIwAxClkQRvMyDylW9Y1wXxEHvWATBfautjc+C0hE9Irjb5wECBX94kUtpYjklgaMbYYQr+ZqSqOETeZABRFj5Ff4Sbh/o1QfCKYuF9NrcMj9HmcyKn0whAzEKC6CTZdNxiMA0UTpiGd3+KSrcSolnBdrmbJ8ij6LLJyiKDIKN/Ocn8WI8cv+bwts038Mct9NfqMgJESd21bz+zL8/dJHw5dobE4edyF6COKa2ucEw1ng8zH5Rpg6nrfRwUmDBE+IYg==" Serie="DET" SubTotal="550.00" TipoDeComprobante="I" Total="638.00" Version="4.0" xmlns:cfdi="http://www.sat.gob.mx/cfd/4" xmlns:detallista="http://www.sat.gob.mx/detallista" 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/detallista http://www.sat.gob.mx/sitio_internet/cfd/detallista/detallista.xsd">
<cfdi:Emisor Nombre="ESCUELA KEMPER URGATE" RegimenFiscal="601" Rfc="EKU9003173C9"/>
<cfdi:Receptor DomicilioFiscalReceptor="57740" Nombre="COMERCIALIZADORA TEODORIKAS" RegimenFiscalReceptor="601" Rfc="CTE950627K46" UsoCFDI="G03"/>
<cfdi:Conceptos>
<cfdi:Concepto Cantidad="10.00" ClaveProdServ="44121706" ClaveUnidad="H87" Descripcion="LAPIZ ADHESIVO" Importe="150.00" NoIdentificacion="1234567890123" ObjetoImp="02" Unidad="Pieza" ValorUnitario="15.00">
<cfdi:Impuestos>
<cfdi:Traslados>
<cfdi:Traslado Base="150.00" Importe="24.00" Impuesto="002" TasaOCuota="0.160000" TipoFactor="Tasa"/>
</cfdi:Traslados>
</cfdi:Impuestos>
</cfdi:Concepto>
<cfdi:Concepto Cantidad="20.00" ClaveProdServ="44121701" ClaveUnidad="H87" Descripcion="BOLIGRAFO AZUL" Importe="400.00" NoIdentificacion="9876543210987" ObjetoImp="02" Unidad="Pieza" ValorUnitario="20.00">
<cfdi:Impuestos>
<cfdi:Traslados>
<cfdi:Traslado Base="400.00" Importe="64.00" Impuesto="002" TasaOCuota="0.160000" TipoFactor="Tasa"/>
</cfdi:Traslados>
</cfdi:Impuestos>
</cfdi:Concepto>
</cfdi:Conceptos>
<cfdi:Impuestos TotalImpuestosTrasladados="88.00">
<cfdi:Traslados>
<cfdi:Traslado Base="550.00" Importe="88.00" Impuesto="002" TasaOCuota="0.160000" TipoFactor="Tasa"/>
</cfdi:Traslados>
</cfdi:Impuestos>
<cfdi:Complemento>
<detallista:detallista contentVersion="1.3.1" documentStatus="ORIGINAL" documentStructureVersion="AMC8.1" type="SimpleInvoiceType">
<detallista:requestForPaymentIdentification>
<detallista:entityType>INVOICE</detallista:entityType>
</detallista:requestForPaymentIdentification>
<detallista:specialInstruction code="ZZZ">
<detallista:text>ENTREGA EN ANDEN 4</detallista:text>
</detallista:specialInstruction>
<detallista:orderIdentification>
<detallista:referenceIdentification type="ON">45009911</detallista:referenceIdentification>
<detallista:ReferenceDate>2025-10-26</detallista:ReferenceDate>
</detallista:orderIdentification>
<detallista:AdditionalInformation>
<detallista:referenceIdentification type="ACE">DEPTO-PERFUMERIA</detallista:referenceIdentification>
</detallista:AdditionalInformation>
<detallista:DeliveryNote>
<detallista:referenceIdentification>REMISION-5566</detallista:referenceIdentification>
<detallista:ReferenceDate>2025-10-27</detallista:ReferenceDate>
</detallista:DeliveryNote>
<detallista:buyer>
<detallista:gln>7504000107903</detallista:gln>
<detallista:contactInformation>
<detallista:personOrDepartmentName>
<detallista:text>ALMACEN CENTRAL</detallista:text>
</detallista:personOrDepartmentName>
</detallista:contactInformation>
</detallista:buyer>
<detallista:seller>
<detallista:gln>7504000107903</detallista:gln>
<detallista:alternatePartyIdentification type="SELLER_ASSIGNED_IDENTIFIER_FOR_A_PARTY">1005</detallista:alternatePartyIdentification>
</detallista:seller>
<detallista:lineItem number="1" type="SimpleInvoiceLineItemType">
<detallista:tradeItemIdentification>
<detallista:gtin>1234567890123</detallista:gtin>
</detallista:tradeItemIdentification>
<detallista:tradeItemDescriptionInformation language="ES">
<detallista:longText>LAPIZ ADHESIVO</detallista:longText>
</detallista:tradeItemDescriptionInformation>
<detallista:invoicedQuantity unitOfMeasure="PCE">10.00</detallista:invoicedQuantity>
<detallista:grossPrice>
<detallista:Amount>15.00</detallista:Amount>
</detallista:grossPrice>
<detallista:netPrice>
<detallista:Amount>15.00</detallista:Amount>
</detallista:netPrice>
<detallista:totalLineAmount>
<detallista:grossAmount>
<detallista:Amount>150.00</detallista:Amount>
</detallista:grossAmount>
<detallista:netAmount>
<detallista:Amount>150.00</detallista:Amount>
</detallista:netAmount>
</detallista:totalLineAmount>
</detallista:lineItem>
<detallista:lineItem number="2" type="SimpleInvoiceLineItemType">
<detallista:tradeItemIdentification>
<detallista:gtin>9876543210987</detallista:gtin>
</detallista:tradeItemIdentification>
<detallista:tradeItemDescriptionInformation language="ES">
<detallista:longText>BOLIGRAFO AZUL</detallista:longText>
</detallista:tradeItemDescriptionInformation>
<detallista:invoicedQuantity unitOfMeasure="PCE">20.00</detallista:invoicedQuantity>
<detallista:grossPrice>
<detallista:Amount>20.00</detallista:Amount>
</detallista:grossPrice>
<detallista:netPrice>
<detallista:Amount>20.00</detallista:Amount>
</detallista:netPrice>
<detallista:totalLineAmount>
<detallista:grossAmount>
<detallista:Amount>400.00</detallista:Amount>
</detallista:grossAmount>
<detallista:netAmount>
<detallista:Amount>400.00</detallista:Amount>
</detallista:netAmount>
</detallista:totalLineAmount>
</detallista:lineItem>
<detallista:totalAmount>
<detallista:Amount>550.00</detallista:Amount>
</detallista:totalAmount>
</detallista:detallista>
</cfdi:Complemento>
</cfdi:Comprobante>
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import base64
import hashlib
import subprocess
from pathlib import Path
from lxml import etree
from M2Crypto.RSA import load_key_string
NS_CFDI = "http://www.sat.gob.mx/cfd/4"
NS_DET = "http://www.sat.gob.mx/detallista"
NS_XSI = "http://www.w3.org/2001/XMLSchema-instance"
DATOS = {
"Comprobante": {
"Version": "4.0",
"Serie": "Serie",
"Folio": "Folio",
"Fecha": "2026-01-14T13:55:11",
"FormaPago": "99",
"SubTotal": "1000.00",
"Moneda": "MXN",
"TipoCambio": "1",
"Total": "1160.00",
"TipoDeComprobante": "I",
"Exportacion": "01",
"MetodoPago": "PPD",
"LugarExpedicion": "20000",
"CondicionesDePago": "CondicionesDePago",
},
"Emisor": {
"Rfc": "EKU9003173C9",
"Nombre": "ESCUELA KEMPER URGATE",
"RegimenFiscal": "601",
},
"Receptor": {
"Rfc": "CTE950627K46",
"Nombre": "COMERCIALIZADORA TEODORIKAS",
"UsoCFDI": "G03",
"DomicilioFiscalReceptor": "57740",
"RegimenFiscalReceptor": "601",
},
"Concepto": {
"ClaveProdServ": "50202306",
"NoIdentificacion": "750100000001",
"Cantidad": "10.00",
"ClaveUnidad": "H87",
"Unidad": "Pieza",
"Descripcion": "REFRESCO COLA",
"ValorUnitario": "100.00",
"Importe": "1000.00",
"ObjetoImp": "02",
},
"TrasladoConcepto": {
"Base": "1000.00",
"Impuesto": "002",
"TipoFactor": "Tasa",
"TasaOCuota": "0.160000",
"Importe": "160.00",
},
"Impuestos": {
"TotalImpuestosTrasladados": "160.00",
},
"TrasladoGlobal": {
"Base": "1000.00",
"Impuesto": "002",
"TipoFactor": "Tasa",
"TasaOCuota": "0.160000",
"Importe": "160.00",
},
}
def _leer_certificado(cer_path: Path) -> tuple[str, str]:
cert_bytes = cer_path.read_bytes()
cert_b64 = base64.b64encode(cert_bytes).decode("utf-8").replace("\n", "").replace("\r", "")
serial_raw = subprocess.check_output(
["openssl", "x509", "-inform", "DER", "-in", str(cer_path), "-noout", "-serial"],
text=True,
).strip()
serial_hex = serial_raw.split("=", 1)[1].strip()
no_certificado = bytes.fromhex(serial_hex).decode("latin1").upper()
return cert_b64, no_certificado
def _parser_xslt_complements(xslt_path: Path):
class LocalResolver(etree.Resolver):
def resolve(self, url, pubid, context):
if "sitio_internet/cfd" in url or "sat.gob.mx" in url:
filename = url.split("/")[-1]
local_path = xslt_path.parent / "complements" / filename
if local_path.exists():
return self.resolve_filename(str(local_path), context)
return None
parser = etree.XMLParser(resolve_entities=True, remove_blank_text=False)
parser.resolvers.add(LocalResolver())
return parser
def _cadena_original(xml_path: Path, xslt_path: Path) -> str:
xml_doc = etree.parse(str(xml_path))
xslt_doc = etree.parse(str(xslt_path), parser=_parser_xslt_complements(xslt_path))
transform = etree.XSLT(xslt_doc)
return (
str(transform(xml_doc))
.replace('<?xml version="1.0" encoding="UTF-8"?>', "")
.replace("\n", "")
.strip()
)
def _sello(cadena: str, key_path: Path) -> str:
key_data = key_path.read_text(encoding="utf-8")
rsa = load_key_string(key_data.encode("utf-8"))
digest = hashlib.sha256(cadena.encode("utf-8")).digest()
firma = rsa.sign(digest, "sha256")
return base64.b64encode(firma).decode("utf-8")
def _sub_text(parent, tag: str, text: str, attrs: dict | None = None):
node = etree.SubElement(parent, tag, **(attrs or {}))
node.text = text
return node
def generar_xml(output_path: Path, cer_path: Path, key_path: Path, xslt_path: Path) -> Path:
etree.register_namespace("cfdi", NS_CFDI)
etree.register_namespace("detallista", NS_DET)
etree.register_namespace("xsi", NS_XSI)
cert_b64, no_certificado = _leer_certificado(cer_path)
root_attrs = {
**DATOS["Comprobante"],
"NoCertificado": no_certificado,
"Certificado": cert_b64,
"Sello": "",
f"{{{NS_XSI}}}schemaLocation": (
f"{NS_CFDI} http://www.sat.gob.mx/sitio_internet/cfd/4/cfdv40.xsd "
f"{NS_DET} http://www.sat.gob.mx/sitio_internet/cfd/detallista/detallista.xsd"
),
}
root = etree.Element(
f"{{{NS_CFDI}}}Comprobante",
root_attrs,
nsmap={
"cfdi": NS_CFDI,
"detallista": NS_DET,
"xsi": NS_XSI,
},
)
etree.SubElement(root, f"{{{NS_CFDI}}}Emisor", **DATOS["Emisor"])
etree.SubElement(root, f"{{{NS_CFDI}}}Receptor", **DATOS["Receptor"])
conceptos = etree.SubElement(root, f"{{{NS_CFDI}}}Conceptos")
concepto = etree.SubElement(conceptos, f"{{{NS_CFDI}}}Concepto", **DATOS["Concepto"])
imp_concepto = etree.SubElement(concepto, f"{{{NS_CFDI}}}Impuestos")
traslados_concepto = etree.SubElement(imp_concepto, f"{{{NS_CFDI}}}Traslados")
etree.SubElement(traslados_concepto, f"{{{NS_CFDI}}}Traslado", **DATOS["TrasladoConcepto"])
imp_global = etree.SubElement(root, f"{{{NS_CFDI}}}Impuestos", **DATOS["Impuestos"])
traslados_global = etree.SubElement(imp_global, f"{{{NS_CFDI}}}Traslados")
etree.SubElement(traslados_global, f"{{{NS_CFDI}}}Traslado", **DATOS["TrasladoGlobal"])
complemento = etree.SubElement(root, f"{{{NS_CFDI}}}Complemento")
det = etree.SubElement(
complemento,
f"{{{NS_DET}}}detallista",
contentVersion="1.3.1",
documentStatus="ORIGINAL",
documentStructureVersion="AMC8.1",
type="SimpleInvoiceType",
)
rpi = etree.SubElement(det, f"{{{NS_DET}}}requestForPaymentIdentification")
_sub_text(rpi, f"{{{NS_DET}}}entityType", "INVOICE")
oi = etree.SubElement(det, f"{{{NS_DET}}}orderIdentification")
_sub_text(
oi,
f"{{{NS_DET}}}referenceIdentification",
"ORD-559988",
{"type": "ON"},
)
_sub_text(oi, f"{{{NS_DET}}}ReferenceDate", "2025-10-25")
ai = etree.SubElement(det, f"{{{NS_DET}}}AdditionalInformation")
_sub_text(
ai,
f"{{{NS_DET}}}referenceIdentification",
"2",
{"type": "ATZ"},
)
buyer = etree.SubElement(det, f"{{{NS_DET}}}buyer")
_sub_text(buyer, f"{{{NS_DET}}}gln", "7504000107903")
seller = etree.SubElement(det, f"{{{NS_DET}}}seller")
_sub_text(seller, f"{{{NS_DET}}}gln", "7504000107903")
_sub_text(
seller,
f"{{{NS_DET}}}alternatePartyIdentification",
"998877",
{"type": "SELLER_ASSIGNED_IDENTIFIER_FOR_A_PARTY"},
)
line_item = etree.SubElement(
det,
f"{{{NS_DET}}}lineItem",
number="1",
type="SimpleInvoiceLineItemType",
)
tii = etree.SubElement(line_item, f"{{{NS_DET}}}tradeItemIdentification")
_sub_text(tii, f"{{{NS_DET}}}gtin", "750100000001")
tdi = etree.SubElement(
line_item,
f"{{{NS_DET}}}tradeItemDescriptionInformation",
language="ES",
)
_sub_text(tdi, f"{{{NS_DET}}}longText", "REFRESCO")
_sub_text(
line_item,
f"{{{NS_DET}}}invoicedQuantity",
"10.00",
{"unitOfMeasure": "PCE"},
)
gross_price = etree.SubElement(line_item, f"{{{NS_DET}}}grossPrice")
_sub_text(gross_price, f"{{{NS_DET}}}Amount", "100.00")
net_price = etree.SubElement(line_item, f"{{{NS_DET}}}netPrice")
_sub_text(net_price, f"{{{NS_DET}}}Amount", "100.00")
tla = etree.SubElement(line_item, f"{{{NS_DET}}}totalLineAmount")
gross_amount = etree.SubElement(tla, f"{{{NS_DET}}}grossAmount")
_sub_text(gross_amount, f"{{{NS_DET}}}Amount", "1000.00")
net_amount = etree.SubElement(tla, f"{{{NS_DET}}}netAmount")
_sub_text(net_amount, f"{{{NS_DET}}}Amount", "1000.00")
total_amount = etree.SubElement(det, f"{{{NS_DET}}}totalAmount")
_sub_text(total_amount, f"{{{NS_DET}}}Amount", "1000.00")
output_path.parent.mkdir(parents=True, exist_ok=True)
etree.ElementTree(root).write(
str(output_path),
encoding="utf-8",
pretty_print=True,
xml_declaration=True,
)
cadena = _cadena_original(output_path, xslt_path)
sello = _sello(cadena, key_path)
tree = etree.parse(str(output_path))
tree.getroot().set("Sello", sello)
tree.write(str(output_path), encoding="utf-8", pretty_print=True, xml_declaration=True)
return output_path
if __name__ == "__main__":
salida = Path("xml/Detallista_py.xml")
cer = Path("certificados/EKU9003173C9/EKU9003173C9.cer")
key = Path("certificados/EKU9003173C9/EKU9003173C9.pem")
xslt = Path("xslt/cfdi/v40/cadenaoriginal.xslt")
archivo = generar_xml(salida, cer, key, xslt)
print(f"XML generado: {archivo}")
<?php
declare(strict_types=1);
date_default_timezone_set('America/Mexico_City');
const NS_CFDI = 'http://www.sat.gob.mx/cfd/4';
const NS_DET = 'http://www.sat.gob.mx/detallista';
const NS_XSI = 'http://www.w3.org/2001/XMLSchema-instance';
$DATA = [
'Comprobante' => [
'Version' => '4.0',
'Serie' => 'Serie',
'Folio' => 'Folio',
'Fecha' => '2026-01-14T13:55:11',
'FormaPago' => '99',
'SubTotal' => '1000.00',
'Moneda' => 'MXN',
'TipoCambio' => '1',
'Total' => '1160.00',
'TipoDeComprobante' => 'I',
'Exportacion' => '01',
'MetodoPago' => 'PPD',
'LugarExpedicion' => '20000',
'CondicionesDePago' => 'CondicionesDePago',
],
'Emisor' => [
'Rfc' => 'EKU9003173C9',
'Nombre' => 'ESCUELA KEMPER URGATE',
'RegimenFiscal' => '601',
],
'Receptor' => [
'Rfc' => 'CTE950627K46',
'Nombre' => 'COMERCIALIZADORA TEODORIKAS',
'UsoCFDI' => 'G03',
'DomicilioFiscalReceptor' => '57740',
'RegimenFiscalReceptor' => '601',
],
'Concepto' => [
'ClaveProdServ' => '50202306',
'NoIdentificacion' => '750100000001',
'Cantidad' => '10.00',
'ClaveUnidad' => 'H87',
'Unidad' => 'Pieza',
'Descripcion' => 'REFRESCO COLA',
'ValorUnitario' => '100.00',
'Importe' => '1000.00',
'ObjetoImp' => '02',
],
'TrasladoConcepto' => [
'Base' => '1000.00',
'Impuesto' => '002',
'TipoFactor' => 'Tasa',
'TasaOCuota' => '0.160000',
'Importe' => '160.00',
],
'Impuestos' => [
'TotalImpuestosTrasladados' => '160.00',
],
'TrasladoGlobal' => [
'Base' => '1000.00',
'Impuesto' => '002',
'TipoFactor' => 'Tasa',
'TasaOCuota' => '0.160000',
'Importe' => '160.00',
],
];
function setAttrs(DOMElement $node, array $attrs): void
{
foreach ($attrs as $k => $v) {
$node->setAttribute((string)$k, (string)$v);
}
}
function textNode(DOMDocument $doc, DOMElement $parent, string $name, string $value, array $attrs = []): DOMElement
{
$node = $doc->createElementNS(NS_DET, $name);
setAttrs($node, $attrs);
$node->appendChild($doc->createTextNode($value));
$parent->appendChild($node);
return $node;
}
function leerCertificado(string $cerPath): array
{
$certBytes = file_get_contents($cerPath);
if ($certBytes === false) {
throw new RuntimeException("No se pudo leer el certificado: {$cerPath}");
}
$certB64 = str_replace(["\n", "\r"], '', base64_encode($certBytes));
$certPem = "-----BEGIN CERTIFICATE-----\n"
. chunk_split(base64_encode($certBytes), 64, "\n")
. "-----END CERTIFICATE-----\n";
$parsed = openssl_x509_parse($certPem);
if ($parsed === false || empty($parsed['serialNumberHex'])) {
throw new RuntimeException('No se pudo obtener serialNumberHex del certificado.');
}
$hex = preg_replace('/\s+/', '', (string)$parsed['serialNumberHex']);
$decoded = hex2bin($hex);
if ($decoded === false || $decoded === '') {
throw new RuntimeException('No se pudo decodificar el serial del certificado.');
}
return [$certB64, strtoupper($decoded)];
}
function cadenaOriginal(string $xmlPath, string $xsltPath): string
{
$xml = new DOMDocument();
if (!$xml->load($xmlPath)) {
throw new RuntimeException("No se pudo cargar XML: {$xmlPath}");
}
$xsl = new DOMDocument();
if (!$xsl->load($xsltPath)) {
throw new RuntimeException("No se pudo cargar XSLT: {$xsltPath}");
}
$proc = new XSLTProcessor();
$proc->importStylesheet($xsl);
$result = $proc->transformToXML($xml);
if ($result === false) {
throw new RuntimeException('No se pudo generar la cadena original con XSLT.');
}
return trim(str_replace(["\n", '<?xml version="1.0"?>'], '', $result));
}
function crearSello(string $cadena, string $keyPath): string
{
$pem = file_get_contents($keyPath);
if ($pem === false) {
throw new RuntimeException("No se pudo leer la llave privada: {$keyPath}");
}
$privateKey = openssl_pkey_get_private($pem);
if ($privateKey === false) {
throw new RuntimeException('No se pudo cargar la llave privada.');
}
$ok = openssl_sign($cadena, $firma, $privateKey, OPENSSL_ALGO_SHA256);
if (!$ok) {
throw new RuntimeException('No se pudo firmar la cadena original.');
}
return base64_encode($firma);
}
function generarXmlDetallista(
string $outputPath,
string $cerPath,
string $keyPath,
string $xsltPath,
array $data
): string {
[$certB64, $noCertificado] = leerCertificado($cerPath);
$doc = new DOMDocument('1.0', 'UTF-8');
$doc->formatOutput = true;
$root = $doc->createElementNS(NS_CFDI, 'cfdi:Comprobante');
$root->setAttributeNS('http://www.w3.org/2000/xmlns/', 'xmlns:detallista', NS_DET);
$root->setAttributeNS('http://www.w3.org/2000/xmlns/', 'xmlns:xsi', NS_XSI);
$root->setAttributeNS(
NS_XSI,
'xsi:schemaLocation',
NS_CFDI . ' http://www.sat.gob.mx/sitio_internet/cfd/4/cfdv40.xsd '
. NS_DET . ' http://www.sat.gob.mx/sitio_internet/cfd/detallista/detallista.xsd'
);
setAttrs($root, $data['Comprobante']);
$root->setAttribute('NoCertificado', $noCertificado);
$root->setAttribute('Certificado', $certB64);
$root->setAttribute('Sello', '');
$doc->appendChild($root);
$emisor = $doc->createElementNS(NS_CFDI, 'cfdi:Emisor');
setAttrs($emisor, $data['Emisor']);
$root->appendChild($emisor);
$receptor = $doc->createElementNS(NS_CFDI, 'cfdi:Receptor');
setAttrs($receptor, $data['Receptor']);
$root->appendChild($receptor);
$conceptos = $doc->createElementNS(NS_CFDI, 'cfdi:Conceptos');
$concepto = $doc->createElementNS(NS_CFDI, 'cfdi:Concepto');
setAttrs($concepto, $data['Concepto']);
$impConcepto = $doc->createElementNS(NS_CFDI, 'cfdi:Impuestos');
$trasladosConcepto = $doc->createElementNS(NS_CFDI, 'cfdi:Traslados');
$trasladoConcepto = $doc->createElementNS(NS_CFDI, 'cfdi:Traslado');
setAttrs($trasladoConcepto, $data['TrasladoConcepto']);
$trasladosConcepto->appendChild($trasladoConcepto);
$impConcepto->appendChild($trasladosConcepto);
$concepto->appendChild($impConcepto);
$conceptos->appendChild($concepto);
$root->appendChild($conceptos);
$impGlobal = $doc->createElementNS(NS_CFDI, 'cfdi:Impuestos');
setAttrs($impGlobal, $data['Impuestos']);
$trasladosGlobal = $doc->createElementNS(NS_CFDI, 'cfdi:Traslados');
$trasladoGlobal = $doc->createElementNS(NS_CFDI, 'cfdi:Traslado');
setAttrs($trasladoGlobal, $data['TrasladoGlobal']);
$trasladosGlobal->appendChild($trasladoGlobal);
$impGlobal->appendChild($trasladosGlobal);
$root->appendChild($impGlobal);
$complemento = $doc->createElementNS(NS_CFDI, 'cfdi:Complemento');
$det = $doc->createElementNS(NS_DET, 'detallista:detallista');
setAttrs($det, [
'contentVersion' => '1.3.1',
'documentStatus' => 'ORIGINAL',
'documentStructureVersion' => 'AMC8.1',
'type' => 'SimpleInvoiceType',
]);
$rpi = $doc->createElementNS(NS_DET, 'detallista:requestForPaymentIdentification');
textNode($doc, $rpi, 'detallista:entityType', 'INVOICE');
$det->appendChild($rpi);
$oi = $doc->createElementNS(NS_DET, 'detallista:orderIdentification');
textNode($doc, $oi, 'detallista:referenceIdentification', 'ORD-559988', ['type' => 'ON']);
textNode($doc, $oi, 'detallista:ReferenceDate', '2025-10-25');
$det->appendChild($oi);
$ai = $doc->createElementNS(NS_DET, 'detallista:AdditionalInformation');
textNode($doc, $ai, 'detallista:referenceIdentification', '2', ['type' => 'ATZ']);
$det->appendChild($ai);
$buyer = $doc->createElementNS(NS_DET, 'detallista:buyer');
textNode($doc, $buyer, 'detallista:gln', '7504000107903');
$det->appendChild($buyer);
$seller = $doc->createElementNS(NS_DET, 'detallista:seller');
textNode($doc, $seller, 'detallista:gln', '7504000107903');
textNode(
$doc,
$seller,
'detallista:alternatePartyIdentification',
'998877',
['type' => 'SELLER_ASSIGNED_IDENTIFIER_FOR_A_PARTY']
);
$det->appendChild($seller);
$lineItem = $doc->createElementNS(NS_DET, 'detallista:lineItem');
setAttrs($lineItem, ['number' => '1', 'type' => 'SimpleInvoiceLineItemType']);
$tii = $doc->createElementNS(NS_DET, 'detallista:tradeItemIdentification');
textNode($doc, $tii, 'detallista:gtin', '750100000001');
$lineItem->appendChild($tii);
$tdi = $doc->createElementNS(NS_DET, 'detallista:tradeItemDescriptionInformation');
setAttrs($tdi, ['language' => 'ES']);
textNode($doc, $tdi, 'detallista:longText', 'REFRESCO');
$lineItem->appendChild($tdi);
textNode($doc, $lineItem, 'detallista:invoicedQuantity', '10.00', ['unitOfMeasure' => 'PCE']);
$grossPrice = $doc->createElementNS(NS_DET, 'detallista:grossPrice');
textNode($doc, $grossPrice, 'detallista:Amount', '100.00');
$lineItem->appendChild($grossPrice);
$netPrice = $doc->createElementNS(NS_DET, 'detallista:netPrice');
textNode($doc, $netPrice, 'detallista:Amount', '100.00');
$lineItem->appendChild($netPrice);
$totalLine = $doc->createElementNS(NS_DET, 'detallista:totalLineAmount');
$grossAmount = $doc->createElementNS(NS_DET, 'detallista:grossAmount');
textNode($doc, $grossAmount, 'detallista:Amount', '1000.00');
$totalLine->appendChild($grossAmount);
$netAmount = $doc->createElementNS(NS_DET, 'detallista:netAmount');
textNode($doc, $netAmount, 'detallista:Amount', '1000.00');
$totalLine->appendChild($netAmount);
$lineItem->appendChild($totalLine);
$det->appendChild($lineItem);
$totalAmount = $doc->createElementNS(NS_DET, 'detallista:totalAmount');
textNode($doc, $totalAmount, 'detallista:Amount', '1000.00');
$det->appendChild($totalAmount);
$complemento->appendChild($det);
$root->appendChild($complemento);
$dir = dirname($outputPath);
if (!is_dir($dir) && !mkdir($dir, 0777, true) && !is_dir($dir)) {
throw new RuntimeException("No se pudo crear directorio de salida: {$dir}");
}
$doc->save($outputPath);
$cadena = cadenaOriginal($outputPath, $xsltPath);
$sello = crearSello($cadena, $keyPath);
$sellado = new DOMDocument();
$sellado->formatOutput = true;
$sellado->load($outputPath);
$sellado->documentElement->setAttribute('Sello', $sello);
$sellado->save($outputPath);
return $outputPath;
}
$base = __DIR__;
$rutaSalida = $base . '/xml/Detallista_php.xml';
$rutaCer = $base . '/certificados/EKU9003173C9/EKU9003173C9.cer';
$rutaKey = $base . '/certificados/EKU9003173C9/EKU9003173C9.pem';
$rutaXslt = $base . '/cadenaoriginal_4_0.xslt';
try {
$archivo = generarXmlDetallista($rutaSalida, $rutaCer, $rutaKey, $rutaXslt, $DATA);
echo "XML generado: {$archivo}\n";
} catch (Throwable $e) {
fwrite(STDERR, "ERROR: " . $e->getMessage() . "\n");
exit(1);
}