Leer un CFDI de Retenciones

Existen otro tipo de CFDI definido en el Anexo 20 sección II adicionales los CFDI de tipo Comprobante <cfdi:Comprobante/> (ingresos, egresos, traslados y pagos).

Este CFDI se llama CFDI de retenciones e información de pagos y tiene la misma esencia de los comprobantes "tradicionales" (definir en campos requeridos, condicionales y obligatorios) pero cuenta con una estructura totalmente diferente.

Acerca de los CFDI de Retenciones e información de pagos

Existe poca información alrededor de este tipo de comprobantes porque su generación es mucho menor a los CFDI tradicionales.

Su obligatoriedad y la información que contienen está sujeta a LIVA, LISR y LIEPS. Si requieres saber si caes en algún supuesto en donde requieras emitir este tipo de comprobantes te recomiendo lo verifiques con tu contador de confianza.

Entre las diferencias fundamentales de CFDI de retenciones y CFDI tradicionales están:

  • El espacio de nombres XML http://www.sat.gob.mx/esquemas/retencionpago/1
  • El nombre de los atributos principales, como retencion:Retenciones@Cert en lugar de cfdi:Comprobante@Certificado
  • Tiene sus propios catálogos de información
  • El sello se procesa usando el algoritmo de digestión SHA1 en lugar de SHA256
  • La fecha se expresa en ISO-8601 (contiene al final -06:00)

Entre las semejanzas están:

  • Se maneja con complementos
  • Puede contener addendas
  • También requiere firmarse por un PAC entregando un Timbre Fiscal Digital

Herramientas gratuitas

Es importante notar que el SAT no cuenta con una herramienta para elaborar CFDI de retenciones e información de pagos como la tiene para los CFDI tradicionales, en su explicación de esquema operativo explican que se requiere utilizar a un PAC para poderlos emitir.

Por otro lado, el SAT no les ha exigido a los PAC que cuenten con herramientas gratuitas para elaborarlos, por lo que generalmente se requerirá contratar el uso de una aplicación o bien contratar los servicios de timbrado.

Con CfdiUtils podrás generar el Pre-CFDI y mandarlo timbrar con tu PAC habitual, el PAC te devolverá el CFDI incluyendo el Timbre Fiscal Digital y este es el comprobante legal.

Más información

Lectura de CFDI de retenciones e información de pagos

La estrategia para leer CFDI de retenciones e información de pagos es la misma que se utiliza para realizar la lectura de CFDI. Consulta la información relacionada con el uso de elementos, nodos y lectura rápida.

Clase CfdiUtils\Retenciones\Retenciones

El objeto que se utiliza para poder hacer la lectura es CfdiUtils\Retenciones\Retenciones. Y lo puedes inicializar por su constructor natural $retenciones = new Retenciones(DOMDocument $document) o con el constructor estático $retenciones = Retenciones::newFromString(string $xmlContent).

Inmutabilidad

El objeto Retenciones es inmutable, es creado con un objeto DOMDocument pero es clonado al momento de su construcción, por lo que si se hacen cambios en este objeto no se verán reflejados en el lector. A su vez, el objeto devuelto por los métodos getDocument() o getNode(), a pesar de ser en sí mismos mutables, no tendrán un impacto en el contenedor.

Versión

El CFDI de retenciones abarca las versiones 1.0 y 2.0, en caso de que se fabrique un objeto que contiene un número de versión diferente, entonces el método Retenciones::getVersion() devolverá una cadena vacía. Esto es por homogeneidad con la lectura de CFDI regulares.

Es importante notar cambios en la estructura y que muchos de los atributos usados en la versión 1.0 cambian de nombre o contenido en la versión 2.0, por lo que se recomienda utilizar diferentes lectores según la versión del comprobante.

Lectura formal

La lectura formal utiliza nodos, que es una representación en memoria del contenido de la estructura XML. En esta forma, los elementos XML se deben acceder utilizando su prefijo y nombre exacto, y los atributos su nombre exacto. Para obtener el nodo raíz se usa el método Retenciones::getNode().

Lectura rápida

La lectura rápida utiliza nodos, que es una representación en memoria del contenido de la estructura XML. En esta forma, a diferencia del modo formal, los elementos se obtienen solo por su nombre simple y los nombres de elementos y atributos no son sensibles a mayúsculas y minúsculas. Para obtener el nodo raíz se usa el método Retenciones::getQuickReader().

Ejemplo de lectura de CFDI de retenciones e información de pagos

<?php

// construir el lector desde un contenido XML
$xmlContent = file_get_contents('cfdi-retenciones-e-informacion-de-pagos.xml');
$reader = \CfdiUtils\Retenciones\Retenciones::newFromString($xmlContent);

// obtener el nodo para lectura formal
$nodeRetenciones = $reader->getNode();
echo $nodeRetenciones->searchAttribute('retenciones:Emisor', 'RFCEmisor'); // EKU9003173C9

// obtener el QuickReader para lectura rápida
$qrRetenciones = $reader->getQuickReader();
echo $qrRetenciones->emisor['NomDenRazSocE']; // Nombre del emisor

Obteniendo la versión de un CFDI de Retenciones sin la clase CfdiUtils\Retenciones\Retenciones

Obtener la versión de un CFDI de Retenciones es sencillo con la clase CfdiUtils\Retenciones\RetencionVersion.

El método que usarás para obtener la versión depende de la información que ya tengas cargada:

  • getFromXmlString(): Cuando ya tienes el contenido del XML en una variable
  • getFromNode(): Cuando tienes el nodo principal en un objeto de tipo CfdiUtils\Nodes\NodeInterface
  • getFromDOMDocument() y getFromDOMElement(): Cuando tienes el contenido XML cargado en un objeto de tipo DOM.

El resultado de estos métodos será un string con el número de versión y vacío en caso de no encontrarse un número de versión compatible.

<?php
$retencionFile = '/retencion/archivo-retencion.xml';
$xmlContents = file_get_contents($retencionFile);
$cfdiVersion = new \CfdiUtils\Retenciones\RetencionVersion();
$version = $cfdiVersion->getFromXmlString($xmlContents);

Nota: la clase CfdiUtils\Retenciones\Retenciones ya realiza este proceso por lo que no es recomendado duplicar el trabajo de averiguar la versión.